//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//
// Copyright (c) 2002 BSQUARE Corporation.  All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE
//
// Module Name:
//
//    SDControl.c
//
// Abstract:
//
//    PXA SDIO controller implementation
//
// Notes:
//
///////////////////////////////////////////////////////////////////////////////

//#define EXTENSIVE_DEBUGGING

#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include "SD.h"

#if(CEATA_CCS_MODE)
HANDLE hCEATACCSIntrEvent;
XLLP_UINT32_T CCSStatus;
#define SYSINTR_CEATACCS 21
#endif

#define DMA_TEST_MODE

#ifdef DMA_TEST_MODE

#include "xllp_dmac.h" 
#include "dmawince.h"
//#include <monahans_base_regs.h>
//#include <monahans_mmc.h>


//#define PAGE_SIZE 0x1000  // ?? Put this is drvglob.h ??  // See ceddk.h
#define	TRANSFER_BUF_SIZE	( 2 * 16 * 0x400)   //  32KB. Good to be multiple of 4KB, the PAGE_SIZE.
												//  Double buffering used for Xmt and Rcv.

#define	NUM_DESC					0x10				// Desc in a Xmt or Rcv chain	 
//#define	NUM_SDIO_XMT_DESC			(2 * NUM_DESC)		// Two Xmt Desc chains
//#define	NUM_SDIO_RCV_DESC			(2 * NUM_DESC)		// Two Rcv Desc chains
#define	NUM_SDIO_XR_DESC			(2 * NUM_DESC)		// Two Desc chains. Xmt or Rcv, but never both.
#define SIZE_SDIO_DESC				sizeof(XLLP_DMAC_DESCRIPTOR_T)


#define TOTAL_BUF_SIZE  (( NUM_SDIO_XR_DESC  * SIZE_SDIO_DESC) + TRANSFER_BUF_SIZE )

typedef enum 
{
    XMT_SDIO,
    RCV_SDIO
} SDIOTRANFER;

typedef struct _NextXRBuffers
{
    volatile XLLP_DMAC_DESCRIPTOR_T *pVirtDescriptor;		// Descriptor Virt Start Addr.
    P_XLLP_DMAC_DESCRIPTOR_T pPhysDescriptor;		// Descriptor Phys Start Addr.
    P_XLLP_INT8_T pStartVirtDataBuffer;	// 	
    P_XLLP_INT8_T pStartPhysDataBuffer;	// 	
    XLLP_UINT32_T Length;					// Bytes specified in Desc chain transfer.
    BOOL MoreDataToTransfer;
} NextXRBuffers;


typedef struct _SDHCDmacDescriptor{
    XLLP_DMAC_CHANNEL_T		RcvChannel ;
    XLLP_DMAC_CHANNEL_T		XmtChannel ;

    HANDLE	DMATxEventHandle ;
    HANDLE	DMARxEventHandle ;

    P_XLLP_DMAC_T	pDMACHandle ;

    XLLP_DMAC_DESCRIPTOR_T		*pDescVirtXR ;	// Used for both Xmt and Rcv.
    P_XLLP_DMAC_DESCRIPTOR_T			 pDescPhysXR ;	// SD/SDIO bus is simplex.

	// Buffer pointers for use with HalAllocateCommonBuffer(...)
    PHYSICAL_ADDRESS		PhysAdr_HalAlloComBuf;
    P_XLLP_UINT8_T			VirtAdr_HalAlloComBuf;

    NextXRBuffers	NextTransfer[2];	// Double buffering for Xmt and Rcv DMA.
    ULONG	i_NT;						// Index for NextTransfer array.
    ULONG	CommittedToRcvNT;			// Total Rcv bytes spec'd in current descriptor set.
	
    _TCHAR			DMAEventName[20];		// 

	//other configures to replace hard code
    XLLP_DMAC_DRCMR_T rxChannel, txChannel;	
}SDHCDmacDescriptor, * PSDHCDmacDescriptor;

//static SDHCDmacDescriptor SDHCDmacDscr;

#endif //end #ifdef DMA_TEST_MODE

    // prototypes
DWORD SDControllerIstThread(PSDH_HARDWARE_CONTEXT pHCDevice);
#ifndef DDEBUG
void DumpRegisters(PSDH_HARDWARE_CONTEXT pController) {}
void DumpGPIORegisters(PSDH_HARDWARE_CONTEXT pController) {}
#endif

#ifdef DEBUG
#define HEXBUFSIZE 1024
char szHexBuf[HEXBUFSIZE];

#define TRANSFER_SIZE(pRequest)            ((pRequest)->BlockSize * (pRequest)->NumBlocks)

char* HexDisplay(PSD_BUS_REQUEST pRequest, BYTE *pBuffer, DWORD dwLength )
{
    DWORD dwTemp = 0;

    // we are touching the block buffer, we must set the process permissions
    SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {
	while( dwTemp < dwLength && (dwTemp < (HEXBUFSIZE / 2 - 1) ) )
	{
		szHexBuf[dwTemp*2] = pBuffer[dwTemp] / 16;
		szHexBuf[dwTemp*2+1] = pBuffer[dwTemp] % 16;
		
		if( szHexBuf[dwTemp*2] < 10 )
			szHexBuf[dwTemp*2] += '0';
		else
			szHexBuf[dwTemp*2] += 'a' - 10;

		if( szHexBuf[dwTemp*2+1] < 10 )
			szHexBuf[dwTemp*2+1] += '0';
		else
			szHexBuf[dwTemp*2+1] += 'a' - 10;

		dwTemp++;
	}
    } SD_RESTORE_PROC_PERMISSIONS();	
	
    szHexBuf[dwTemp*2] = 0;

    return szHexBuf;
}

#endif

__inline void WRITE_MMC_REGISTER_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset, DWORD Value) 
{
    BYTE *pRegBaseAddr, *regAddr;
    volatile DWORD *pdwRegAddr;
    pRegBaseAddr = (BYTE*)(pHc->pSDMMCRegisters);
    regAddr = pRegBaseAddr + RegOffset;
    pdwRegAddr = (DWORD*)regAddr;
    *pdwRegAddr = Value;
}

__inline DWORD READ_MMC_REGISTER_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset)
{
    BYTE *pRegBaseAddr, *regAddr;
    volatile DWORD *pdwRegAddr;
    pRegBaseAddr = (BYTE*)(pHc->pSDMMCRegisters);
    regAddr = pRegBaseAddr + RegOffset;
    pdwRegAddr = (DWORD*)regAddr;
    return (*pdwRegAddr);
}

#define IS_PROGRAM_DONE(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_PROGRAM_DONE)
#define IS_TRANSFER_DONE(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_DATA_TRANSFER_DONE)

//#define RX_FIFO_FULL(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_RCV_FIFO_FULL)
//#define TX_FIFO_EMPTY(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_XMIT_FIFO_EMPTY)

#define TRANSFER_IS_WRITE(pRequest) ((SD_WRITE == (pRequest)->TransferClass))
#define TRANSFER_IS_READ(pRequest)  ((SD_READ == (pRequest)->TransferClass))

BOOL CLOCK_IS_ON(PSDH_HARDWARE_CONTEXT pHc)
{
    if( READ_MMC_REGISTER_DWORD( pHc, MMC_STAT ) & MMC_STAT_CLOCK_ENABLED )
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

__inline void READ_MOD_WRITE_MMC_REGISTER_AND_OR(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset, DWORD AndValue, DWORD OrValue)
{
    DWORD regValue;
    regValue = READ_MMC_REGISTER_DWORD(pHc, RegOffset);
    regValue &= (AndValue);
    regValue |= (OrValue);
    DEBUGMSG(SDCARD_ZONE_INFO, (TEXT("SHCDriver: - Setting MMC Reg 0x%x to 0x%x\r\n"), RegOffset, regValue));
    WRITE_MMC_REGISTER_DWORD(pHc, RegOffset, regValue);
}

__inline void WRITE_MMC_IMASK_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD Value) 
{
    EnterCriticalSection(&(pHc->intrRegCriticalSection));
    WRITE_MMC_REGISTER_DWORD( pHc, MMC_IMASK, Value);
    LeaveCriticalSection(&(pHc->intrRegCriticalSection));
}

__inline DWORD READ_MMC_IMASK_DWORD(PSDH_HARDWARE_CONTEXT pHc)
{
    DWORD dwRetVal;
    EnterCriticalSection(&(pHc->intrRegCriticalSection));
    dwRetVal = READ_MMC_REGISTER_DWORD( pHc, MMC_IMASK );
    LeaveCriticalSection(&(pHc->intrRegCriticalSection));
    return dwRetVal;
}

__inline void READ_MOD_WRITE_MMC_IMASK_AND_OR(PSDH_HARDWARE_CONTEXT pHc, DWORD AndValue, DWORD OrValue)
{
    EnterCriticalSection(&(pHc->intrRegCriticalSection));
    READ_MOD_WRITE_MMC_REGISTER_AND_OR( pHc, MMC_IMASK, AndValue, OrValue );
    LeaveCriticalSection(&(pHc->intrRegCriticalSection));
}

#define CLOCK_OFF_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_CLOCK_OFF_INT_MASKED)
 
    // macro to turn SDIO interrupts on
#define SDIO_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_SDIO_INT_MASKED, 0)

    // macro to turn SDIO interrupts off
#define SDIO_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_SDIO_INT_MASKED)

    // macro to turn RX FIFO interrupts on
#define RX_FIFO_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_RXFIFO_REQ_INT_MASKED, 0)

    // macro to turn RX FIFO interrupts off
#define RX_FIFO_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_RXFIFO_REQ_INT_MASKED)

    // macro to turn TX FIFO interrupts on
#define TX_FIFO_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_TXFIFO_REQ_INT_MASKED, 0)

    // macro to turn TX FIFO interrupts off
#define TX_FIFO_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_TXFIFO_REQ_INT_MASKED)

#define TRANSFER_DONE_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_DATA_TRAN_DONE_INT_MASKED, 0) 

#define TRANSFER_DONE_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_DATA_TRAN_DONE_INT_MASKED) 

#define END_CMD_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_END_CMD_INT_MASKED, 0) 

#define END_CMD_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_END_CMD_INT_MASKED) 

#define PROGRAM_DONE_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_PROG_DONE_INT_MASKED, 0) 

#define PROGRAM_DONE_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_PROG_DONE_INT_MASKED) 

#define PROGRAM_DATA_ERROR_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_DATA_ERROR_INT_MASKED, 0) 

#define PROGRAM_DATA_ERROR_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_DATA_ERROR_INT_MASKED) 

#define PROGRAM_RESPONSE_ERROR_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_RESPONSE_ERROR_INT_MASKED, 0) 

#define PROGRAM_RESPONSE_ERROR_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_RESPONSE_ERROR_INT_MASKED) 

#define TX_BUFFER_PARTIAL_FULL(pHc) \
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_PRTBUF, MMC_PRTBUF_BUFFER_PARTIAL_FULL)
   
#define TX_BUFFER_PARTIAL_NOT_FULL(pHc) \
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_PRTBUF, 0)

#define ALL_INTERRUPTS_OFF(pHc) \
    READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_ALL_INTERRUPTS_MASKED) 

    // clock rate table
typedef struct _CLOCK_RATE_ENTRY {
    DWORD Frequency;
    UCHAR ControlValue;
} CLOCK_RATE_ENTRY, *PCLOCK_RATE_ENTRY;

CLOCK_RATE_ENTRY SDClockTable[] = 
{   {312500,  0x06},
    {625000,   0x05},
    {1250000,  0x04},
    {2500000,  0x03},
    {5000000,  0x02},
    {10000000, 0x01},
    {20000000, 0x00},   // 20 Mhz
};

#define NUM_CLOCK_ENTRIES sizeof(SDClockTable)/sizeof(CLOCK_RATE_ENTRY)


#ifdef DMA_TEST_MODE

///////////////////////////////////////////////////////////////////////////////
//  SDDmaInit - Allocate/setup structures and mappings for DMA operation.
//  Input:  None
//  Output: 
//  Return:
//  Notes:  
//
///////////////////////////////////////////////////////////////////////////////
BOOL SDDmacInit(PSDH_HARDWARE_CONTEXT pHardwareContext)     //  Call this from within SDInitialize(...)
{

    P_XLLP_UINT8_T         pbVirtDMATemp;
    P_XLLP_UINT8_T         pbPhysDMATemp;
    P_XLLP_UINT8_T         pbVirtTransferBuf;
    P_XLLP_UINT8_T         pbPhysTransferBuf;
    PHYSICAL_ADDRESS          PA;
    DMA_ADAPTER_OBJECT    Adapter;

	PSDHCDmacDescriptor pSDHCDmacDscr;

	NextXRBuffers * pNextTransfer;

	XLLP_DMAC_DRCMR_T txChannels[3]={XLLP_DMAC_MMC_TX, XLLP_DMAC_MMC_2_TX, XLLP_DMAC_MMC_3_TX};
	XLLP_DMAC_DRCMR_T rxChannels[3]={XLLP_DMAC_MMC_RX, XLLP_DMAC_MMC_2_RX, XLLP_DMAC_MMC_3_RX};

    ////alloc & set sdhcDMACDscr
    if( !(pSDHCDmacDscr = (PSDHCDmacDescriptor)malloc( sizeof(SDHCDmacDescriptor) )) )
    {
        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("SDH: Failed to allocate extension\n")));
        return 0;
    }
    memset( pSDHCDmacDscr, 0, sizeof(SDHCDmacDescriptor) );	
	pHardwareContext->DmacDscr=pSDHCDmacDscr;
	pSDHCDmacDscr=(PSDHCDmacDescriptor)pHardwareContext->DmacDscr;

	pSDHCDmacDscr->rxChannel= rxChannels[pHardwareContext->dwSDHCIndex -1];
	pSDHCDmacDscr->txChannel= txChannels[pHardwareContext->dwSDHCIndex -1];
	
    // Setup the DMA Controller (DMAC)
    if(NULL == (pSDHCDmacDscr->pDMACHandle = GdeDmacInit()) )
    {
        NKDbgPrintfW((TEXT("[MMC][ERROR]: fail to GdeDmacInit()! \r\n")));
        return FALSE;   // Failed.
    }

    // Allocate contigous, physical memory for data buffers and descriptors.
    Adapter.ObjectSize    = sizeof(DMA_ADAPTER_OBJECT);
    Adapter.InterfaceType = Internal;
    Adapter.BusNumber     = 0;

    pbVirtDMATemp =  (P_XLLP_UINT8_T)HalAllocateCommonBuffer(&Adapter, TOTAL_BUF_SIZE , &PA, FALSE);
    if (!pbVirtDMATemp)
    {
        NKDbgPrintfW(TEXT("[MMC][ERROR]:  failed to SDDmacInit()!\r\n"));
        return(FALSE);
    }

    // Save Virtual and Physical pointers for use in deInitialize routines.
    pSDHCDmacDscr->PhysAdr_HalAlloComBuf = PA;
    pSDHCDmacDscr->VirtAdr_HalAlloComBuf = pbVirtDMATemp;

    pbPhysDMATemp = (BYTE *)PA.LowPart;
    // Xmt/Rcv Descriptors.
    pSDHCDmacDscr->pDescVirtXR = (P_XLLP_DMAC_DESCRIPTOR_T)pbVirtDMATemp;
    pSDHCDmacDscr->pDescPhysXR = (P_XLLP_DMAC_DESCRIPTOR_T)pbPhysDMATemp;

    //  // rcv Descriptors.
    //
    //  pDescVirtRcv = pDescVirtXmt + NUM_SDIO_XR_DESC;
    //  pDescPhysRcv = pDescPhysXmt + NUM_SDIO_XR_DESC;

    // Data Buffers.
    pbVirtTransferBuf = (P_XLLP_INT8_T)(pSDHCDmacDscr->pDescVirtXR + NUM_SDIO_XR_DESC);
    pbPhysTransferBuf = (P_XLLP_INT8_T)(pSDHCDmacDscr->pDescPhysXR + NUM_SDIO_XR_DESC);

    pSDHCDmacDscr->i_NT = 0;

    //  Note that the same descriptor pointers and transfer buffer pointers
    //  are used for both Xmt and Rcv since a bus request must complete before 
    //  the next one is processed. Thus Xmt and Rcv are mutually exclusive.

	pNextTransfer=pSDHCDmacDscr->NextTransfer;
	
    pNextTransfer[0].pVirtDescriptor          = pSDHCDmacDscr->pDescVirtXR;
    pNextTransfer[0].pPhysDescriptor         = pSDHCDmacDscr->pDescPhysXR;
    pNextTransfer[0].pStartVirtDataBuffer  = pbVirtTransferBuf; 
    pNextTransfer[0].pStartPhysDataBuffer = pbPhysTransferBuf; 
    pNextTransfer[0].MoreDataToTransfer     = TRUE; 
	
    pNextTransfer[1].pVirtDescriptor          = pSDHCDmacDscr->pDescVirtXR + ( NUM_SDIO_XR_DESC/2 );
    pNextTransfer[1].pPhysDescriptor         = pSDHCDmacDscr->pDescPhysXR + ( NUM_SDIO_XR_DESC/2 );
    pNextTransfer[1].pStartVirtDataBuffer  = pbVirtTransferBuf + (TRANSFER_BUF_SIZE/2);
    pNextTransfer[1].pStartPhysDataBuffer = pbPhysTransferBuf + (TRANSFER_BUF_SIZE/2);
    pNextTransfer[1].MoreDataToTransfer     = TRUE; 

    // Obtain DMA channel for Xmt.
    if(XLLP_STATUS_SUCCESS != GdeDmacAllocChannel(  &(pSDHCDmacDscr->XmtChannel),  XLLP_DMAC_CHANNEL_PRIORITY_HIGH))
    {
        NKDbgPrintfW(TEXT("[MMC] fail to XllpDmacAllocChannel(Tx) ! \r\n"));
        return SD_API_STATUS_PENDING;
    }
    // Create a Named Event for use during the Xmt operation. 
    _stprintf(pSDHCDmacDscr->DMAEventName, TEXT("DMA_CHANNEL_%d"), pSDHCDmacDscr->XmtChannel); // Compose the name.
    pSDHCDmacDscr->DMATxEventHandle = CreateEvent(NULL,FALSE,FALSE, pSDHCDmacDscr->DMAEventName); 

    // Obtain DMA channel for Recv.
    if(XLLP_STATUS_SUCCESS != GdeDmacAllocChannel(  &(pSDHCDmacDscr->RcvChannel),  XLLP_DMAC_CHANNEL_PRIORITY_LOW))
    {
        NKDbgPrintfW(TEXT("[MMC] fail to XllpDmacAllocChannel(Rx) !\r\n"));
        return SD_API_STATUS_PENDING;
    }
    // Create a Named Event for use during the Xmt operation. 
    _stprintf(pSDHCDmacDscr->DMAEventName, TEXT("DMA_CHANNEL_%d"), pSDHCDmacDscr->RcvChannel); // Compose the name.
    pSDHCDmacDscr->DMARxEventHandle = CreateEvent(NULL,FALSE,FALSE, pSDHCDmacDscr->DMAEventName);

    // Exit
    RETAILMSG(SDDEBUG, (TEXT("[%s] successfully SDDmacInit()\r\n"), pHardwareContext->szName)); 
    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
//  SDDmaInit - setup structure and mappings for DMA operation.
//  Input:  None
//  Output: 
//  Return:
//  Notes:  
//
///////////////////////////////////////////////////////////////////////////////
BOOL SDDmacDeInit(PSDH_HARDWARE_CONTEXT pHardwareContext)
{
    DMA_ADAPTER_OBJECT     Adapter;
	PSDHCDmacDescriptor pSDHCDmacDscr=pHardwareContext->DmacDscr;

    // DeAllocate contigous, physical memory for data buffers and descriptors.
    Adapter.ObjectSize    = sizeof(DMA_ADAPTER_OBJECT);
    Adapter.InterfaceType = Internal;
    Adapter.BusNumber     = 0;
	

    if (NULL != pSDHCDmacDscr->VirtAdr_HalAlloComBuf)
    {
        HalFreeCommonBuffer( &Adapter, TOTAL_BUF_SIZE , 
                                pSDHCDmacDscr->PhysAdr_HalAlloComBuf, pSDHCDmacDscr->VirtAdr_HalAlloComBuf, 
                                FALSE);
	 pSDHCDmacDscr->VirtAdr_HalAlloComBuf = NULL;
    }

    // Free Channel and and the event used by the DMA Engine.
	GdeDmacFreeChannel( pSDHCDmacDscr->XmtChannel, pSDHCDmacDscr->txChannel );
	GdeDmacFreeChannel( pSDHCDmacDscr->RcvChannel, pSDHCDmacDscr->rxChannel );

    pSDHCDmacDscr->XmtChannel = (XLLP_DMAC_CHANNEL_T) 0xFFFFFFFF; //invalid, dummy
    pSDHCDmacDscr->RcvChannel = (XLLP_DMAC_CHANNEL_T) 0xFFFFFFFF; //invalid, dummy
    if (NULL != pSDHCDmacDscr->DMATxEventHandle)
    {
        CloseHandle(pSDHCDmacDscr->DMATxEventHandle);
        pSDHCDmacDscr->DMATxEventHandle = NULL;
    }
    if (NULL != pSDHCDmacDscr->DMARxEventHandle)
    {
        CloseHandle(pSDHCDmacDscr->DMARxEventHandle);
        pSDHCDmacDscr->DMARxEventHandle = NULL;
    }
	
	if(NULL != pSDHCDmacDscr)	
		free(pSDHCDmacDscr);
    // Exit
    return TRUE;
}
#endif // end #ifdef DMA_TEST_MODE


//return value is original status
BOOL SDCKENOnOff(PSDH_HARDWARE_CONTEXT pHc, BOOL on)
{
    if(pHc->fSDCKENOn!=on)
    {
        XLLP_BOOL_T xllp_on=(on)?XLLP_TRUE:XLLP_FALSE;
        XllpClockEnable((P_XLLP_CLKMGR_T)pHc->pClkMgrRegisters, pHc->MMCClkModule, xllp_on);
        RETAILMSG(SDDEBUG,(TEXT("SDCKEN: %d+++++++++++++\r\n"), on));
        pHc->fSDCKENOn=on;
    }
    return pHc->fSDCKENOn;
}

///////////////////////////////////////////////////////////////////////////////
//  SDClockOff - turn off the MMC clock
//  Input:  pHc - hardware context
//  Output: 
//  Return:
//  Notes:  
//
///////////////////////////////////////////////////////////////////////////////
VOID SDClockOff(PSDH_HARDWARE_CONTEXT pHc)
{
    int i=100;
        // check to see if the clock is on
    if (!CLOCK_IS_ON(pHc)) {
        return;
    }

    DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("SDClockOff - turning off clock \r\n")));
        // turn off the clock
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_STRPCL, MMC_STRPCL_STOP_CLOCK);
    //RETAILMSG(1, (TEXT("SDClockOff - turning off clock \r\n")));

    while (i-->0 && CLOCK_IS_ON(pHc)) {
        // sit here and wait for the clock to turn off
        RETAILMSG(SDDEBUG, (TEXT("[%s]waiting for sd clock off...........\r\n"), pHc->szName));
        DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("Waiting for clock off \r\n")));
    }

    if(i<=0)
        RETAILMSG(1, (TEXT("[%s]WARNING!!waiting for sd clock off...........FAILED!\r\n"), pHc->szName));

    DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("SDClockOff - Clock is now off \r\n")));
}

///////////////////////////////////////////////////////////////////////////////
//  SDClockOn - turn on the MMC Clock
//  Input:  pHc - hardware context
//  Output: 
//  Return:
//  Notes:  
//          
//
///////////////////////////////////////////////////////////////////////////////
VOID SDClockOn(PSDH_HARDWARE_CONTEXT pHc)
{
    // check to see if the clock is on
    if (CLOCK_IS_ON(pHc)) {
        return;
    }
	
   // turn on the clock
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_STRPCL, MMC_STRPCL_START_CLOCK);
      RETAILMSG(SDDEBUG, (TEXT("SDClockOn - turning on clock \r\n")));
}

///////////////////////////////////////////////////////////////////////////////
//  SDSetRate - set the rate of MMC Clock
//  Input:  pHc - hardware context
//          pRate - pointer to desired clock rate in Hz
//  Output:
//  Return: 
//  Notes:  
//
///////////////////////////////////////////////////////////////////////////////
VOID SDSetRate(PSDH_HARDWARE_CONTEXT pHc, PDWORD pRate)
    {
    ULONG ii;           // table index variable
    DWORD rate;
    BOOL fClockRunning;
    BOOL fCKENOn;
	
    EnterCriticalSection(&pHc->csMiniOPCriticalSection);  

    fClockRunning = CLOCK_IS_ON(pHc);
    //when set rate, make sure CKEN on
    fCKENOn=SDCKENOnOff(pHc, TRUE);
    SDClockOff(pHc);

    rate = *pRate;
    if( rate > pHc->dwMaximumSDClockFrequency )
        rate = pHc->dwMaximumSDClockFrequency;	
        
    // check to see if the rate is below the first entry in the table
    if (rate <= SDClockTable[0].Frequency)
        ii = 0;
    else if (rate >= SDClockTable[NUM_CLOCK_ENTRIES - 1].Frequency)
        // check to see if the rate is above the last entry in the table
        ii = NUM_CLOCK_ENTRIES - 1;
    else
        {
        // scan through the table looking for the highest frequency that is <= requested frquency.
        // The <= is so that if the requestor has determined the max frequency based on a card's CSD response
        // we don't exceed the card's stated maximum.
        for (ii = (NUM_CLOCK_ENTRIES - 1); ii > 0; ii--)
            {
            if (SDClockTable[ii].Frequency <= rate)
                break;
            }
        }

    RETAILMSG(SDDEBUG, (TEXT("[%s] SDSetRate - Requested Rate: %d, Setting clock rate to %d Hz (%d)\r\n"), pHc->szName, *pRate, SDClockTable[ii].Frequency, SDClockTable[ii].ControlValue));

        // return the actual fruency selected
    *pRate = SDClockTable[ii].Frequency;

        // set the clock rate
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_CLKRT, SDClockTable[ii].ControlValue);

    pHc->dwSDClockFrequency = SDClockTable[ii].Frequency;

    if( fClockRunning )
    {
        SDClockOn( pHc );
    }	
    else if( !fCKENOn )
    {
        SDCKENOnOff( pHc, FALSE);
    }

    LeaveCriticalSection(&pHc->csMiniOPCriticalSection);
	
}

BOOL SDAdjustRate(PSDH_HARDWARE_CONTEXT pHc)
{
    if(SDClockTable[0].Frequency>= pHc->dwSDClockFrequency)
    {
        RETAILMSG(1, (TEXT("[%s]: Clk to buttom %d to %d\r\n"), pHc->szName, 
			pHc->dwSDClockFrequency));
        return FALSE;
    }
    //RETAILMSG(1, (TEXT("[%s]: Clk adjusted from %d to %d\r\n"), pHc->szName, 
	//		pHc->dwSDClockFrequency, (pHc->dwSDClockFrequency)/2));
    pHc->dwSDClockFrequency/=2;//adjust to lower level
    SDSetRate( pHc, &pHc->dwSDClockFrequency);
    pHc->fClkAdjusted=TRUE;
    return TRUE;
}

void SDCheckRate(PSDH_HARDWARE_CONTEXT pHc)
{
    if( (!pHc->fClkAdjusted) && (pHc->dwWorkClkRate!=pHc->dwSDClockFrequency))
    {
        //after a fail-adjust-successful cmd: 
        //currently we don't set it back to avoid fail-lower-up-fail cycle
        //RETAILMSG(1, (TEXT("[%s]: Set clk back from %d to %d\r\n"), pHc->szName, 
        //		pHc->dwSDClockFrequency, pHc->dwWorkClkRate));
        //SDSetRate(pHc, &pHc->dwWorkClkRate);
    }
    else if( (pHc->fClkAdjusted) && (pHc->dwWorkClkRate==pHc->dwSDClockFrequency))
    {
        RETAILMSG(1, (TEXT("[%s]: IT SHOULD NEVER HAPPEN!!!!!!!!!!!!!!\r\n"), pHc->szName));
    }
    //clean it anyway....
    pHc->fClkAdjusted=FALSE;
}

static void DoBusRequestPrepare(PSDH_HARDWARE_CONTEXT pController)
{
    pController->fCMD= TRUE;
	
    //check it
    SDCheckRate(pController);

    EnterCriticalSection(&pController->csMiniOPCriticalSection);        
    if (FALSE == pController->fMiniOPSet){
        // Send Proc Notify to IPM to signify more restrictions.
        DWORD dwProcState = IPM_PROCESSOR_D0_RDY | IPM_PROCESSOR_RING_OSC_RDY; 
        // Notify IPM 
        RETAILMSG(1, (_T("[%s] Notify IPM Ready For Processor state. dwProcState=%x\r\n"),pController->szName,dwProcState));
        if ( IPM_STATUS_SUCCESS!=IPM_NotifyReadyForProcState(pController->ClientID, dwProcState ,3000)){
            RETAILMSG(1, (_T("[%s] Notify IPM Ready For Processor state FAILED \r\n"),pController->szName));
        }
        /*   set IPM minop
        RETAILMSG(1, (_T("[%s] Setting MinOP \r\n"),pController->szName));
        if ( IPM_STATUS_SUCCESS!=IPM_SetMinOp(pController->ClientID, IPM_OP_624MHZ ,3000)){
            RETAILMSG(1, (_T("[%s] MinOP Set FAILED\r\n"),pController->szName));
        }*/
        if (NULL != pController->hClockOn)
        {
            SetEvent(pController->hClockOn);
        }
        pController->fMiniOPSet = TRUE;
    }
    SDCKENOnOff( pController, TRUE);
    SDClockOn(pController);
    LeaveCriticalSection(&pController->csMiniOPCriticalSection);
}

static void DoBusRequestFinish(PSDH_HARDWARE_CONTEXT pController)
{
}

SD_API_STATUS SDBusIssueRequest(PSDCARD_HC_CONTEXT pHCContext, 
                                     DWORD              Slot, 
                                     PSD_BUS_REQUEST    pRequest) ;

static BOOL IndicateBusRequestComplete(PSDCARD_HC_CONTEXT pHCContext,
                                    PSD_BUS_REQUEST pRequest,
                                    SD_API_STATUS      Status)
{
    BOOL fRet = FALSE;
    PSDH_HARDWARE_CONTEXT pController = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHCContext);
    if (pController && pController->pCurrentRequest == pRequest) {
        //if it's really a bus request complete, DoBusRequestFinish first
        DoBusRequestFinish(pController);


        //CRC error->resend
        if(SD_API_STATUS_CRC_ERROR == Status)
        {
            //RETAILMSG(1, (_T("[%s] CRC error-> adjust the clock rate resend\r\n"),pController->szName));
	    if(SDAdjustRate(pController))
            {
                Status=SDBusIssueRequest(pHCContext, 0, pRequest);
                if(SD_API_STATUS_PENDING == Status)
                {
                    //RETAILMSG(1, (_T("[%s] CRC error-> re-send successfully\r\n"),pController->szName));
                    return FALSE;
                }
            }
        }
			
        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("IndicateBusRequestComplete - pRequest = %x, Status = %d\n"),pRequest,Status));
        pController->pCurrentRequest = NULL;
        if (pController->fCurrentRequestFastPath ) {
            if (Status == SD_API_STATUS_SUCCESS) {
                Status = SD_API_STATUS_FAST_PATH_SUCCESS;
            }
            pController->FastPathStatus = Status ;
        }
        else
	{
	       RETAILMSG(SDDEBUG, (TEXT("[%s] IndicateBusRequestComplete - pRequest = %x, Status = %d\n"),pController->szName, pRequest,Status));
             SDHCDIndicateBusRequestComplete(pHCContext,pRequest,Status);
	}	
        fRet = TRUE;
    }
    ASSERT(fRet);
    return fRet;
}

///////////////////////////////////////////////////////////////////////////////
//  SDDeInitialize - Deinitialize the the MMC Controller
//  Input:  pHCContext - Host controller context
//          
//  Output: 
//  Return: SD_API_STATUS code
//  Notes:  
//         
//
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS SDDeinitialize(PSDCARD_HC_CONTEXT pHCContext)
{
    PSDH_HARDWARE_CONTEXT pHardwareContext; // hardware context
    

	
    pHardwareContext = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHCContext);
    RETAILMSG(SDDEBUG, (TEXT("[%s] SDDeinitialize()+\r\n"),   pHardwareContext->szName)); 

        // make sure all interrupt sources are disabled
    InterruptDisable (pHardwareContext->dwSysintrSDMMC);

        // mark for shutdown
    pHardwareContext->DriverShutdown = TRUE;

        // clean up card insertion IST and free card insertion interrupt
    CleanupCardDetectIST(pHardwareContext);

        // clean up controller IST
    if (NULL != pHardwareContext->hControllerInterruptThread) {
            // wake up the IST
        SetEvent(pHardwareContext->hControllerInterruptEvent);
            // wait for the thread to exit
        WaitForSingleObject(pHardwareContext->hControllerInterruptThread, INFINITE); 
        CloseHandle(pHardwareContext->hControllerInterruptThread);
        pHardwareContext->hControllerInterruptThread = NULL;
    }
        
        // free controller interrupt event
    if (NULL != pHardwareContext->hControllerInterruptEvent) {
        CloseHandle(pHardwareContext->hControllerInterruptEvent);
        pHardwareContext->hControllerInterruptEvent = NULL;
    }
    
        // free memory mapped resources

    if (NULL != pHardwareContext->pSDMMCRegisters) {
        MmUnmapIoSpace((PVOID)pHardwareContext->pSDMMCRegisters, sizeof(PXA_MMC_REG));
        pHardwareContext->pSDMMCRegisters = NULL;
    }

    if (NULL != pHardwareContext->pGPIORegisters) {
        MmUnmapIoSpace((PVOID)pHardwareContext->pGPIORegisters, sizeof(PXA_GPIO_REG));
        pHardwareContext->pGPIORegisters = NULL;
    }

    if (NULL != pHardwareContext->pClkMgrRegisters) {
        MmUnmapIoSpace((PVOID)pHardwareContext->pClkMgrRegisters, sizeof(PXA_CLKMGR_REG));
        pHardwareContext->pClkMgrRegisters = NULL;
    }

    if (NULL != pHardwareContext->pDMARegisters) {
        MmUnmapIoSpace((PVOID)pHardwareContext->pDMARegisters, sizeof(PXA_DMA_REG));
        pHardwareContext->pDMARegisters = NULL;
    }

    if (NULL != pHardwareContext->pOSTRegisters) {
        MmUnmapIoSpace((PVOID)pHardwareContext->pOSTRegisters, sizeof(PXA_OST_REG));
        pHardwareContext->pOSTRegisters = NULL;
    }

    if (NULL != pHardwareContext->pMFPRegisters) {
        MmUnmapIoSpace((PVOID)pHardwareContext->pMFPRegisters, 0x700);
        pHardwareContext->pMFPRegisters = NULL;
    }
	
    if (NULL != pHardwareContext->m_MfpRMDbHandle)
	CloseHandle(pHardwareContext->m_MfpRMDbHandle);

    UnInitializeHardware(pHardwareContext);

#ifdef DMA_TEST_MODE
    SDDmacDeInit(pHardwareContext);
#endif

    DeleteCriticalSection(&pHardwareContext->ControllerCriticalSection);
    DeleteCriticalSection(&pHardwareContext->intrRegCriticalSection);

    RETAILMSG(SDDEBUG, (TEXT("[%s] SDDeinitialize()-\r\n"),pHardwareContext->szName)); 
    return SD_API_STATUS_SUCCESS;
}


///////////////////////////////////////////////////////////////////////////////
//  SDInitialize - Initialize the the MMC Controller
//  Input:  pHardwareContext - newly allocated hardware context
//          
//  Output: 
//  Return: SD_API_STATUS code
//  Notes:  
//          
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS SDInitialize(PSDCARD_HC_CONTEXT pHCContext)
{
    DWORD dwSDIOIrq;
    SD_API_STATUS status = SD_API_STATUS_SUCCESS;   // intermediate status
    DWORD         threadID;                         // thread ID
    PSDH_HARDWARE_CONTEXT pHardwareContext;       // hardware context

    PHYSICAL_ADDRESS PXA_GPIO_Base = {MONAHANS_BASE_REG_PA_GPIO};
    PHYSICAL_ADDRESS PXA_CLKMGR_Base = {MONAHANS_BASE_REG_PA_CLKMGR};
    PHYSICAL_ADDRESS PXA_DMA_Base = {MONAHANS_BASE_REG_PA_DMAC};
    PHYSICAL_ADDRESS PXA_MFP_Base = {MONAHANS_BASE_REG_PA_MFP};
    PHYSICAL_ADDRESS PXA_OST_Base = {MONAHANS_BASE_REG_PA_OST};
    PHYSICAL_ADDRESS PXA_BPMU_Base = {MONAHANS_BASE_REG_PA_BPMU};

    DWORD PXA_SDMMC_Base_Addr[3] = {MONAHANS_BASE_REG_PA_MMC, MONAHANS_BASE_REG_PA_MMC2, MONAHANS_BASE_REG_PA_MMC3};
		
    XLLP_CLK_MODULE  xllp_clk_mmc[3] = {XLLP_CLK_MMC0, XLLP_CLK_MMC1, XLLP_CLK_MMC3};
	
    P_XLLP_MFP_RM_DB_ID_T pMfpRMDb;
    BOOL bFirstInit;
    XLLP_STATUS_T returnValue = XLLP_STATUS_FAILURE;

    pHardwareContext=GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHCContext);

    RETAILMSG(SDDEBUG, (TEXT("[%s] SDInitialize()+\r,index:%d,\n"), pHardwareContext->szName, pHardwareContext->dwSDHCIndex)); 

    InitializeCriticalSection(&pHardwareContext->ControllerCriticalSection);

    pHardwareContext->fSDIOEnabled = FALSE;
    pHardwareContext->pCurrentRequest = NULL ;
    pHardwareContext->fSDIOInterruptPending = FALSE;
    pHardwareContext->f4BitMode = FALSE;
    pHardwareContext->DevicePresent = FALSE;
    pHardwareContext->fSDCKENOn = FALSE;

    InitializeCriticalSection(&pHardwareContext->intrRegCriticalSection);

	//some variables set here
    pHardwareContext->MMCClkModule=xllp_clk_mmc[pHardwareContext->dwSDHCIndex -1];
    pHardwareContext->PhysicalRegBase=PXA_SDMMC_Base_Addr[pHardwareContext->dwSDHCIndex -1];		

    if( !InitializeHardware(pHardwareContext) )
    {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error initializing platform specific hardware\r\n")));
        return SD_API_STATUS_INSUFFICIENT_RESOURCES;
    }

#ifdef DMA_TEST_MODE
        // Setup for DMA Transfers.   
    if(!SDDmacInit(pHardwareContext) )
    {
        NKDbgPrintfW(TEXT("[MMC][ERROR] fail to SDDmacInit() ! \r\n"));
        return SD_API_STATUS_INSUFFICIENT_RESOURCES;
    }
#endif

    pHardwareContext->pGPIORegisters = (PXA_GPIO_REG*)MmMapIoSpace( PXA_GPIO_Base, sizeof(PXA_GPIO_REG), FALSE );
    if ( !pHardwareContext->pGPIORegisters )
    {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error allocating GPIO registers\r\n")));
        return SD_API_STATUS_INSUFFICIENT_RESOURCES;
    }
    {
        PHYSICAL_ADDRESS PXA_SDMMC_Base={pHardwareContext->PhysicalRegBase};
        pHardwareContext->pSDMMCRegisters = (PXA_MMC_REG*)MmMapIoSpace( PXA_SDMMC_Base, sizeof(PXA_MMC_REG), FALSE );
        if ( !pHardwareContext->pSDMMCRegisters )
        {
            DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error allocating SD/MMC registers\r\n")));
            status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
            goto exitInit;
        }
    }

    pHardwareContext->pClkMgrRegisters = (PXA_CLKMGR_REG*)MmMapIoSpace( PXA_CLKMGR_Base, sizeof(PXA_CLKMGR_REG), FALSE );
    if ( !pHardwareContext->pClkMgrRegisters )
    {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error allocating Clock control registers\r\n")));
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit;
    }

    pHardwareContext->pDMARegisters = (PXA_DMA_REG*)MmMapIoSpace( PXA_DMA_Base, sizeof(PXA_DMA_REG), FALSE );
    if ( !pHardwareContext->pDMARegisters )
    {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error allocating  DMA control registers\r\n")));
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit;
    }

    pHardwareContext->pOSTRegisters = (PXA_OST_REG*)MmMapIoSpace( PXA_OST_Base, sizeof(PXA_OST_REG), FALSE );
    if ( !pHardwareContext->pOSTRegisters )
    {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error allocating  OST control registers\r\n")));
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit;
    }

    pHardwareContext->pMFPRegisters = (unsigned int	 *)MmMapIoSpace( PXA_MFP_Base, 0x700, FALSE );
    if ( !pHardwareContext->pMFPRegisters )
    {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error allocating  MFP control registers\r\n")));
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit;
    }

    pHardwareContext->pBPMURegisters = (P_XLLP_PM_BPMU_T)MmMapIoSpace( PXA_BPMU_Base, sizeof(XLLP_PM_BPMU_T), FALSE );
    if ( !pHardwareContext->pBPMURegisters )
    {
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("InitializeHardware:: Error allocating  BPMU control registers\r\n")));
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit;
    }

    // Claim memory-mapped file for sharing MfpRmDb information.
    pHardwareContext->m_MfpRMDbHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
			0, XLLP_MFP_RM_DB_SIZE, MFPRMDB_SHARED_FILENAME );

    if (NULL == pHardwareContext->m_MfpRMDbHandle)
    {
        NKDbgPrintfW(TEXT("[MMC] Fail to CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n"));
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit; //if failed
    } else {

        // We need to tell if it's first or sequent call of  CreateFileMapping(MFPRMDB_SHARED_FILENAME)
        if (ERROR_ALREADY_EXISTS != GetLastError()) {
            // The first initialization of this memory-mapped file.
            RETAILMSG(1, (TEXT("[%s] First call of CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n"), pHardwareContext->szName));		

            bFirstInit = TRUE;		
        } else {
            // Memory-mapped file already existed.
            RETAILMSG(1, (TEXT("[%s] Sequent call of CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n"), pHardwareContext->szName));

            bFirstInit = FALSE;
        }

	  // Retrieve the local handle of the global shared memory-mapped file
        pMfpRMDb = (P_XLLP_MFP_RM_DB_ID_T) MapViewOfFile(pHardwareContext->m_MfpRMDbHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
        if (NULL == pMfpRMDb)
        {
            NKDbgPrintfW(TEXT("[MMC] Fail to MapViewOfFile()!\r\n"));
            status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
            goto exitInit;//if failed
        }

        if (TRUE == bFirstInit) {
            // Need to Initialize RM	
            if (XLLP_STATUS_SUCCESS != XllpMfpResourceManagerInit(pMfpRMDb)) {
	            NKDbgPrintfW(TEXT("[MMC] Fail to XllpMfpResourceManagerInit()!\r\n"));
                    status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
                    goto exitInit; //if failed
            }
        }
        
    }// end if (NULL == pHardwareContext->m_MfpRMDbHandle)

    //Initialize MMC's GPIO settings		
    pHardwareContext->XllpMMCContext.pGPIOReg = (P_XLLP_GPIO_T)pHardwareContext->pGPIORegisters;
    pHardwareContext->XllpMMCContext.pMFPBase = pHardwareContext->pMFPRegisters;
    pHardwareContext->XllpMMCContext.pMFPRmDb = pMfpRMDb;
    pHardwareContext->XllpMMCContext.pOSTReg = (P_XLLP_OST_T)pHardwareContext->pOSTRegisters;
	//pHardwareContext->XllpMMCContext.pMMC1Reg = NULL;
    //pHardwareContext->XllpMMCContext.pMMC2Reg = (P_XLLP_MMC_T)pHardwareContext->pSDMMCRegisters;
    returnValue = XllpMMCConfigure(
                            (XLLP_MMC_CONTROLLER_ID_T)(pHardwareContext->dwSDHCIndex -1), 
                            &(pHardwareContext->XllpMMCContext)
                            );

    if (XLLP_STATUS_SUCCESS != returnValue ) {
        NKDbgPrintfW(TEXT("\r\n[MMC] Fail to XllpMMCConfigure().\r\n"));
        RETAILMSG(1,(TEXT("[%s] Fail to XllpMMCConfigure(): Code#%x.\r\n"), pHardwareContext->szName, returnValue));

        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit; //if failed
    }

	//now select slot moved to xllpmmcconfigure
	//XllpMMCSelectSlot(&(pHardwareContext->XllpMMCContext), XLLP_MMC_SLOT_0);
	// disble the MMC Unit Clock - will enable it after card inserted
    //XllpClockEnable((P_XLLP_CLKMGR_T)pHardwareContext->pClkMgrRegisters, pHardwareContext->MMCClkModule, XLLP_FALSE); 
    SDCKENOnOff(pHardwareContext, FALSE);

    DumpRegisters( pHardwareContext );

#ifdef DEBUG
    DumpRegisters( pHardwareContext );
    DumpGPIORegisters( pHardwareContext );
#endif

    // allocate the interrupt event
    pHardwareContext->hControllerInterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL);
    
    if (NULL == pHardwareContext->hControllerInterruptEvent) {
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
	NKDbgPrintfW(TEXT("[MMC] Fail to init Controller Interrupt Event!\r\n"));
        goto exitInit;
    }
        // convert the hardware SD/MMC controller interrupt IRQ into a logical SYSINTR value
    dwSDIOIrq = pHardwareContext->dwSDMMCIrq;
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwSDIOIrq, sizeof(DWORD), &(pHardwareContext->dwSysintrSDMMC), sizeof(DWORD), NULL))
    {
        // invalid SDIO SYSINTR value!
        DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("Error obtaining SDIO SYSINTR value!\r\n")));
	NKDbgPrintfW(TEXT("[MMC] Error obtaining SDIO SYSINTR value!\r\n"));
        pHardwareContext->dwSysintrSDMMC = SYSINTR_UNDEFINED;
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
        goto exitInit;
    }

    RETAILMSG(SDDEBUG, (TEXT("[%s] dwSDIOIrq: %d, dwSysintrSDMMC: %d, hControllerInterruptEvent: 0x%x \r\n"), pHardwareContext->szName,dwSDIOIrq, pHardwareContext->dwSysintrSDMMC, pHardwareContext->hControllerInterruptEvent));
        // initialize the interrupt event
    if (!InterruptInitialize (pHardwareContext->dwSysintrSDMMC,
                              pHardwareContext->hControllerInterruptEvent,
                              NULL,
                              0)) {
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
  	NKDbgPrintfW(TEXT("[MMC] Fail to initialize Controller Interrupt!\r\n"));
        goto exitInit;
    }

    pHardwareContext->DriverShutdown = FALSE;
    
        // create the interrupt thread for controller interrupts
    pHardwareContext->hControllerInterruptThread = CreateThread(NULL,
                                                      0,
                                                      (LPTHREAD_START_ROUTINE)SDControllerIstThread,
                                                      pHardwareContext,
                                                      0,
                                                      &threadID);

    if (NULL == pHardwareContext->hControllerInterruptThread) {
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
	NKDbgPrintfW(TEXT("[MMC] Failure in hControllerInterruptThread!\r\n"));
        goto exitInit;
    }
	
    if (!SetupCardDetectIST(pHardwareContext))
    {
        status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
    }

#if(CEATA_CCS_MODE)
    if(FALSE==SDHCISFORCEATA(pHardwareContext))
        goto exitInit;
	
    if(hCEATACCSIntrEvent == NULL)
    {
        hCEATACCSIntrEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("CEATA_CCS_INTERRUPT"));
        if (hCEATACCSIntrEvent == NULL)
        {
            RETAILMSG(1, (TEXT("SDInitialize: hCEATACCSIntrEvent=x%08x(x%x)\r\n"),
				hCEATACCSIntrEvent, GetLastError()));
            return(1);
        }
        if (!InterruptInitialize(SYSINTR_CEATACCS, hCEATACCSIntrEvent, NULL, 0))
        {
            RETAILMSG(1,(TEXT("SDInitialize: InterruptInitialize(hCEATACCSIntrEvent=x%08x) FAILED (x%x)\r\n"),
                      hCEATACCSIntrEvent,GetLastError()));
            return(1);
            }
        RETAILMSG(1,(TEXT("SDInitialize: CEATA CCS InterruptInitialize done\r\n")));
	}
#endif
	
exitInit:

	
    if (!SD_API_SUCCESS(status)) {
            // just call the deinit handler directly to cleanup
        RETAILMSG(SDDEBUG, (TEXT("[%s] faill to SDInitialize()\r\n"), pHardwareContext->szName)); 
        NKDbgPrintfW(TEXT("[MMC] faill to SDInitialize()\r\n"));			
        SDDeinitialize(pHCContext);
    }

    RETAILMSG(SDDEBUG, (TEXT("[%s] SDInitialize()-\r\n"),    pHardwareContext->szName)); 

    return status;

}

///////////////////////////////////////////////////////////////////////////////
//  SDHCancelIoHandler - io cancel handler 
//  Input:  pHostContext - host controller context
//          Slot - slot the request is going on
//          pRequest - the request to be cancelled
//          
//  Output: 
//  Return: TRUE if the request was cancelled
//  Notes:  
//          
//
///////////////////////////////////////////////////////////////////////////////
BOOLEAN SDHCancelIoHandler(PSDCARD_HC_CONTEXT pHCContext, 
                             DWORD              Slot, 
                             PSD_BUS_REQUEST    pRequest)
{
    PSDH_HARDWARE_CONTEXT    pController;

        // for now, we should never get here because all requests are non-cancelable
        // the hardware supports timeouts so it is impossible for the controller to get stuck
    DEBUG_ASSERT(FALSE);

        // get our extension 
    pController = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHCContext);

        // --- Stop hardware, cancel the request!

        // release the lock before we complete the request
    SDHCDReleaseHCLock(pHCContext);
 
        // complete the request with a cancelled status
    IndicateBusRequestComplete(pHCContext,
                                    pRequest,
                                    SD_API_STATUS_CANCELED);

    return TRUE;
}

#ifdef DMA_TEST_MODE

///////////////////////////////////////////////////////////////////////////////
//  CreateSDIODescChainXR - Create Descriptor Chain for optimzed SDIO transfers
//  Input:  
//          
//          
//          
//  Output: 
//  Notes:
//
//
///////////////////////////////////////////////////////////////////////////////
BOOL CreateSDIODescChainXR( 
				PSDH_HARDWARE_CONTEXT pHardwareContext,
				volatile XLLP_DMAC_DESCRIPTOR_T    *pDescVirtXR, 
				P_XLLP_DMAC_DESCRIPTOR_T              pDescPhysXR, 
				UCHAR                            *pPhysDataBufferXR, 
				ULONG                             numbytes,
				SDIOTRANFER                         XmtRcv)
{
    
    ULONG                 nbrDescsXR;
    XLLP_DMAC_COMMAND_T     SdioCmdXR;
    USHORT                  i;
    ULONG                 tmp_numbytes;

    tmp_numbytes = numbytes;

    nbrDescsXR = numbytes/PAGE_SIZE + (numbytes%PAGE_SIZE ? 1 : 0 );
    //--NKDbgPrintfW(TEXT("nbrDescsXR = %d ...  \r\n"), nbrDescsXR);
    
    for(i=0; i < nbrDescsXR; i++)
    {
        // Descriptor Command.

        if(numbytes > (ULONG)PAGE_SIZE)
        {
            SdioCmdXR.aLen        = (XLLP_INT16_T)PAGE_SIZE; // pkdebug. Orig.
            numbytes -= PAGE_SIZE;
        }
        else
        {
            SdioCmdXR.aLen        = (XLLP_INT16_T)numbytes; // pkdebug. Orig.
            numbytes = 0;
        }

        SdioCmdXR.aWidth       = XLLP_DMAC_WIDTH_8;     // 8-bit XMT FIFO
        SdioCmdXR.aSize         = XLLP_DMAC_BURSTSIZE_32;   // 32 entry burst
        SdioCmdXR.aEndian     = XLLP_FALSE;   // Little Endian.
        SdioCmdXR.aEndIrqEn     = 0 == numbytes ? XLLP_TRUE : XLLP_FALSE; 
                                                    // Interrupt when len = 0 for last desc.
        SdioCmdXR.aStartIrqEn = XLLP_FALSE;   // No Interrupt when Desc is loaded.
        SdioCmdXR.aFlowTrg    = XMT_SDIO == XmtRcv ? XLLP_TRUE  : XLLP_FALSE ; // Flow Control the XMT FIFO.
        SdioCmdXR.aFlowSrc    = XMT_SDIO == XmtRcv ? XLLP_FALSE : XLLP_TRUE  ; 
        SdioCmdXR.aIncTrgAddr = XMT_SDIO == XmtRcv ? XLLP_FALSE : XLLP_TRUE  ; // Target is XMT FIFO.
        SdioCmdXR.aIncSrcAddr = XMT_SDIO == XmtRcv ? XLLP_TRUE  : XLLP_FALSE ; // Source is memory.

        // Create descriptor that points to adjacent desciptor.
        GdeDmacFillLinkedDesc(
                                (P_XLLP_DMAC_DESCRIPTOR_T)(pDescVirtXR + i),
                                (P_XLLP_DMAC_DESCRIPTOR_T)(pDescPhysXR + i + 1),
                                0 == numbytes ? XLLP_DMAC_DESC_STOP_CHANNEL : XLLP_DMAC_DESC_RUN_CHANNEL,
                                                    // Stop channel at last desc.
                                XLLP_DMAC_DISABLE_DESC_BRANCH,
                                XMT_SDIO == XmtRcv ? (XLLP_UINT32_T)(pPhysDataBufferXR + i * PAGE_SIZE) :
//                                                   (XLLP_UINT32_T) &(((P_XLLP_MMC_T)MMC_BASE_PHYSICAL)->MB_RXFIFO), // Src addr.
                                                     (XLLP_UINT32_T) &(((PPXA_MMC_REG)(pHardwareContext->PhysicalRegBase))->rxfifo),   // Src addr.
//                              XMT_SDIO == XmtRcv ? (XLLP_UINT32_T) &(((P_XLLP_MMC_T)MMC_BASE_PHYSICAL)->MB_TXFIFO) :
                                XMT_SDIO == XmtRcv ? (XLLP_UINT32_T) &(((PPXA_MMC_REG)(pHardwareContext->PhysicalRegBase))->txfifo):
                                                     (XLLP_UINT32_T)(pPhysDataBufferXR + i * PAGE_SIZE),             // Trg addr.
                                &SdioCmdXR
                              );
    }


//  for(i=0; i < nbrDescsXR; i++)
//  {
//      NKDbgPrintfW(TEXT("\r\n >>> idx = %d <<< (pDescPhys + %d) = %08x, GDE_PHYS_XMT_SDIO_DESC_ARRAY = %08x \r\n"), i, i, (pDescPhysXR + i), GDE_PHYS_XMT_SDIO_DESC_ARRAY );  // pkdebug.
//
//      NKDbgPrintfW(TEXT("         NextD = %08x \r\n"), pDescVirtXR[i].DDADR );  // pkdebug.
//      NKDbgPrintfW(TEXT("         Src   = %08x \r\n"), pDescVirtXR[i].DSADR );  // pkdebug.
//      NKDbgPrintfW(TEXT("         Dest  = %08x \r\n"), pDescVirtXR[i].DTADR );  // pkdebug.
//      NKDbgPrintfW(TEXT("         Cmd   = %08x \r\n"), pDescVirtXR[i].DCMD );   // pkdebug.
//
//      NKDbgPrintfW(TEXT(" ==> Phys( pDescVirtXR + %d ) = %08x \r\n"), i, XllpDmacGetPhysicalAds((P_XLLP_UINT8_T)(pDescVirtXR + i))    );  // pkdebug
//  }

    
//  if(XMT_SDIO == XmtRcv)
//  {
//       NKDbgPrintfW(TEXT("  Xmt-NUMBYTES =  %d ( %08x ) \r\n"), tmp_numbytes, tmp_numbytes  );  // pkdebug
//  }      
//  else
//  {
//       NKDbgPrintfW(TEXT("  Rcv-NUMBYTES =  %d ( %08x ) \r\n"), tmp_numbytes, tmp_numbytes  );  // pkdebug
//  }

    return TRUE;

}

#endif // end #ifdef DMA_TEST_MODE


///////////////////////////////////////////////////////////////////////////////
//  SDBusIssueRequest - bus request handler 
//  Input:  pHostContext - host controller context
//          Slot - slot the request is going on
//          pRequest - the request
//          
//  Output: 
//  Return: SD_API_STATUS Code
//  Notes:  The request passed in is marked as uncancelable, this function
//          has the option of making the outstanding request cancelable    
//          
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS SDBusIssueRequest(PSDCARD_HC_CONTEXT pHCContext, 
                                     DWORD              Slot, 
                                     PSD_BUS_REQUEST    pRequest) 
{

    BOOL fExtraDelay = FALSE;
    PSDH_HARDWARE_CONTEXT    pController;     // our controller
    DWORD                      cmdatRegister;   // CMDAT register



#ifdef DMA_TEST_MODE
	PSDHCDmacDescriptor pSDHCDmacDscr;
	NextXRBuffers * NextTransfer;
    // Local Varribles
    DWORD           maxBytes;       // max bytes
    PUCHAR          pUserBuf;       // pointer to request data buffer
#endif


    DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("SDBusIssueRequest - pRequest = %x, CMD: 0x%02X DATA: 0x%08X, TC: %d\n"),
            pRequest,pRequest->CommandCode, pRequest->CommandArgument, pRequest->TransferClass));

        // get our extension 
    pController = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHCContext);
#ifdef DMA_TEST_MODE
	pSDHCDmacDscr=(PSDHCDmacDescriptor)pController->DmacDscr;

    NextTransfer=pSDHCDmacDscr->NextTransfer;

#endif	
    DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("SDBusIssueRequest - CMD: 0x%02X DATA: 0x%08X, TC: %d\r\n"),
            pRequest->CommandCode, pRequest->CommandArgument, pRequest->TransferClass));

    //request prepare: set clock & IPM status
    DoBusRequestPrepare(pController);

        // set the command
    WRITE_MMC_REGISTER_DWORD(pController, MMC_CMD, pRequest->CommandCode);

    RETAILMSG(SDDEBUG, (TEXT("[%s] SDBusIssueRequest: command=%d,  TansferType=%d (0:RD, 1:WR, 2:CMD)\r\n"), pController->szName, pRequest->CommandCode, pRequest->TransferClass));
        // set the argument,  high part
    WRITE_MMC_REGISTER_DWORD(pController, MMC_ARGH, (pRequest->CommandArgument >> 16));

	// set the argument, low part
    if ((pRequest->CommandCode == 52) && ((pRequest->CommandArgument>>31)==0) ) {		
		//by the spec. if it's a read operation on 52 the data part of argl should be zero
		// we needn't do this after the global macros like BUILD_IO_RW_DIRECT_ARG are refined in sdcard.h
		WRITE_MMC_REGISTER_DWORD(pController, MMC_ARGL, (pRequest->CommandArgument & 0x0000FF00));
    } else {

		WRITE_MMC_REGISTER_DWORD(pController, MMC_ARGL, (pRequest->CommandArgument & 0x0000FFFF));
    }


    switch (pRequest->CommandResponse.ResponseType) {

        case NoResponse:
            cmdatRegister = MMC_CMDAT_RESPONSE_NONE;
            break;
        case ResponseR1b:
                // response1 with busy signalling
            cmdatRegister = MMC_CMDAT_RESPONSE_R1 | MMC_CMDAT_EXPECT_BUSY;
            break;
	    //R7 is for CMD8 only and the format is same to r1...
	    case ResponseR7:
        case ResponseR1:
        case ResponseR5:
        case ResponseR6:
                // on an MMC controller R5 and R6 are really just an R1 response (CRC protected)
            cmdatRegister = MMC_CMDAT_RESPONSE_R1;
            break;
        case ResponseR2:    
            cmdatRegister = MMC_CMDAT_RESPONSE_R2;
            break;
        case ResponseR3:
        case ResponseR4:    
                // R4 is really same as an R3 response on an MMC controller (non-CRC)
            cmdatRegister = MMC_CMDAT_RESPONSE_R3;
            break;

        default:
            DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("SDBusIssueRequest failed (Invalid parameter)\n")));
            return SD_API_STATUS_INVALID_PARAMETER;
    }

        // check for Command Only
    if ((SD_COMMAND == pRequest->TransferClass)) {
       
            // set the length of the block
        WRITE_MMC_REGISTER_DWORD(pController, MMC_BLKLEN, 0);

            // set the number of blocks
        WRITE_MMC_REGISTER_DWORD(pController, MMC_NOB, 0);

    } else {
            // its a command with a data phase
        cmdatRegister |= MMC_CMDAT_DATA_EN;
        
            // set the buffer index to the end of the buffer
        pRequest->HCParam = 0;      

            // set the length of the block
        WRITE_MMC_REGISTER_DWORD(pController, MMC_BLKLEN, pRequest->BlockSize);

            // set the number of blocks
        WRITE_MMC_REGISTER_DWORD(pController, MMC_NOB, pRequest->NumBlocks);

            // check for write
        if (TRANSFER_IS_WRITE(pRequest)) {
            cmdatRegister |= MMC_CMDAT_DATA_WRITE;

#ifdef DMA_TEST_MODE

            maxBytes = pRequest->NumBlocks * pRequest->BlockSize;
            pUserBuf = &pRequest->pBlockBuffer[pRequest->HCParam];

            // Compose XMT Descriptors

            // Block buffer may be in another process, so get permission to read/write that memory.
            SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {  

            // Setup default values in the tranfer control data structure NextTransfer.
            //  i.e. This is the first transfer; multiple buffer transfers are needed.

            pSDHCDmacDscr->i_NT = 0;
		
	     NextTransfer[0].MoreDataToTransfer     = TRUE;       

            NextTransfer[1].MoreDataToTransfer     = TRUE; 
            // First Buffer and Descriptor. 
            if( (maxBytes - pRequest->HCParam) > TRANSFER_BUF_SIZE/2 )
            {
                NextTransfer[0].Length  = TRANSFER_BUF_SIZE/2;
            }
            else  // It all fits in the first buffer.
            {
                NextTransfer[0].Length  = maxBytes - pRequest->HCParam;
                NextTransfer[1].MoreDataToTransfer = FALSE;
            }

            // It is faster to memcpy and create optimized descriptors than to use a MDL, i.e.
            // a Memory Descriptor List.
            memcpy( NextTransfer[0].pStartVirtDataBuffer, 
                    &pRequest->pBlockBuffer[pRequest->HCParam], NextTransfer[0].Length );
            // Use HCParam to track the bytes the descriptor chain will transmit.
            pRequest->HCParam   += NextTransfer[0].Length;  

            // Create Xmt Descriptor chain using this optimzed routine which takes 
            // advantage of the fact that the HalAllocateCommonBuffer routine provides 
            // a buffer that is both virtually and physically contiguous. Note, that it 
            // is faster to memcpy and create optimized descriptors than use a MDL.
            CreateSDIODescChainXR( 
            		pController,
                    NextTransfer[0].pVirtDescriptor, 
                    NextTransfer[0].pPhysDescriptor, 
                    NextTransfer[0].pStartPhysDataBuffer, 
                    NextTransfer[0].Length,
                    XMT_SDIO);
            // Second Buffer and Descriptor.
            if( (maxBytes - pRequest->HCParam) > TRANSFER_BUF_SIZE/2 )
            {  
                NextTransfer[1].Length  = TRANSFER_BUF_SIZE/2;
            }
            else  // It all fits in the second buffer.
            {
                NextTransfer[1].Length  = maxBytes - pRequest->HCParam;
                if(0 == NextTransfer[1].Length)
                {
                    NextTransfer[1].MoreDataToTransfer = FALSE; 
                }
            }
            memcpy( NextTransfer[1].pStartVirtDataBuffer, 
                    &pRequest->pBlockBuffer[pRequest->HCParam], NextTransfer[1].Length );
            pRequest->HCParam   += NextTransfer[1].Length;

            CreateSDIODescChainXR( 
                    pController,
                    NextTransfer[1].pVirtDescriptor, 
                    NextTransfer[1].pPhysDescriptor, 
                    NextTransfer[1].pStartPhysDataBuffer, 
                    NextTransfer[1].Length,
                    XMT_SDIO);

            } SD_RESTORE_PROC_PERMISSIONS();
        
            // Config DMA Channel

            XllpDmacCfgChannelDescTransfer(
                                            pSDHCDmacDscr->pDMACHandle,
                                            NextTransfer[0].pPhysDescriptor,
                                            pSDHCDmacDscr->XmtChannel,
                                            pSDHCDmacDscr->txChannel);

#endif   //  DMA_TEST_MODE
        } 

#ifdef DMA_TEST_MODE

        if (TRANSFER_IS_READ(pRequest))
        {

            maxBytes = pRequest->NumBlocks * pRequest->BlockSize;
            pUserBuf = &pRequest->pBlockBuffer[pRequest->HCParam];

            // Setup default values in the tranfer control data structure NextTransfer.
            //  i.e. This is the first transfer; multiple buffer transfers are needed.
    
            pSDHCDmacDscr->i_NT                 = 0;
            pSDHCDmacDscr->CommittedToRcvNT      = 0;

            NextTransfer[0].MoreDataToTransfer     = TRUE; 

            NextTransfer[1].MoreDataToTransfer     = TRUE; 


            // First Buffer and Descriptor.
            if( (maxBytes - pSDHCDmacDscr->CommittedToRcvNT) > TRANSFER_BUF_SIZE/2 )
            {  
                NextTransfer[0].Length  = TRANSFER_BUF_SIZE/2;
            }
            else  // It all fits in the first buffer.
            {
                NextTransfer[0].Length  = maxBytes - pSDHCDmacDscr->CommittedToRcvNT;
                NextTransfer[1].MoreDataToTransfer = FALSE;
            }

            // Create Rcv Descriptor chain using this optimzed routine which takes 
            // advantage of the fact that the HalAllocateCommonBuffer routine provides
            // a buffer that is both virtually and physically contiguous.  Note, that it 
            // is faster to memcpy and create optimized descriptors than use a MDL

            CreateSDIODescChainXR( 
            		pController,
                    NextTransfer[0].pVirtDescriptor, 
                    NextTransfer[0].pPhysDescriptor, 
                    NextTransfer[0].pStartPhysDataBuffer, 
                    NextTransfer[0].Length,
                    RCV_SDIO);

            // Count the number of bytes for which DMA descriptors are committed. 
    
            pSDHCDmacDscr->CommittedToRcvNT += NextTransfer[0].Length;
    
            // Second Buffer and Descriptor.
            if( (maxBytes - pSDHCDmacDscr->CommittedToRcvNT) > TRANSFER_BUF_SIZE/2 )
            {  
                NextTransfer[1].Length  = TRANSFER_BUF_SIZE/2;
            }
            else  // It all fits in the second buffer.
            {
                NextTransfer[1].Length  = maxBytes - pSDHCDmacDscr->CommittedToRcvNT;
                if(0 == NextTransfer[1].Length)
                {
                    NextTransfer[1].MoreDataToTransfer = FALSE; 
                }
            }

            CreateSDIODescChainXR( 
                    pController,
                    NextTransfer[1].pVirtDescriptor, 
                    NextTransfer[1].pPhysDescriptor, 
                    NextTransfer[1].pStartPhysDataBuffer, 
                    NextTransfer[1].Length,
                    RCV_SDIO);


            pSDHCDmacDscr->CommittedToRcvNT += NextTransfer[1].Length;


            // Config DMA Channel

            XllpDmacCfgChannelDescTransfer(
                                     pSDHCDmacDscr->pDMACHandle,            
                                     NextTransfer[0].pPhysDescriptor,
                                     pSDHCDmacDscr->RcvChannel,
                                     pSDHCDmacDscr->rxChannel);

        }

#endif


        
    }

        // check to see if we need to append the 80 clocks (i.e. this is the first transaction)
    if (pController->SendInitClocks) {
        pController->SendInitClocks = FALSE;
        cmdatRegister |= MMC_CMDAT_INIT;
        fExtraDelay = TRUE;
    }

        // check to see if we need to enable the SDIO interrupt checking
    if (pController->fSDIOEnabled) {
        cmdatRegister |= MMC_CMDAT_SDIO_INT_EN;
    }

        // check to see if we need to enable wide bus (4 bit) data transfer mode
    if (pController->f4BitMode) {
        cmdatRegister |= MMC_CMDAT_SD_4DAT;
    }

#ifdef DMA_TEST_MODE
    cmdatRegister |= MMC_CMDAT_DMA_ENABLE;

    // Protocol requires write to CMDAT before Read operation can start.
    if (TRANSFER_IS_READ(pRequest))
    {
        // Start the Transfer.
        XllpDmacStartTransfer(pSDHCDmacDscr->pDMACHandle, pSDHCDmacDscr->RcvChannel );
        //NKDbgPrintfW(TEXT("RcvChannel Start...\r\n"));
    }

    // Start DMA Xmt.
    if (TRANSFER_IS_WRITE(pRequest))
    {
        XllpDmacStartTransfer(pSDHCDmacDscr->pDMACHandle, pSDHCDmacDscr->XmtChannel );
        //NKDbgPrintfW(TEXT("XmtChannel Start...\r\n"));
    }
#endif

        // set the the response timeout
    WRITE_MMC_REGISTER_DWORD(pController, MMC_RESTO, SDH_DEFAULT_RESPONSE_TIMEOUT_CLOCKS);
        // set the data receive timeout
    WRITE_MMC_REGISTER_DWORD(pController, MMC_RDTO, SDH_DEFAULT_DATA_TIMEOUT_CLOCKS);

    SetCurrentState(pController, CommandSend);
    RETAILMSG(SDDEBUG,(TEXT("[%s] SetCurrentState-CommandSend\r\n"), pController->szName));
        // turn on just the command complete interrupt
    END_CMD_INTERRUPT_ON(pController);

        // write the CMDAT register
    WRITE_MMC_REGISTER_DWORD(pController, MMC_CMDAT, cmdatRegister);
    RETAILMSG(SDDEBUG, (TEXT("[%s] SDBusIssueRequest - CMDAT Reg: 0x%08X, CMD:%d ,0x%x\n"), pController->szName,
                cmdatRegister, pRequest->CommandCode, pController->PhysicalRegBase));
	
    if( fExtraDelay )
    {
        fExtraDelay = FALSE;
        Sleep(500);
    }
       
#if DEBUG
    {
        DWORD mmcStatus;

        mmcStatus = READ_MMC_REGISTER_DWORD(pController, MMC_STAT);

        if (mmcStatus & 0x0000003F) {
                // these errors should be cleared
            DbgPrintZo(SDCARD_ZONE_ERROR, 
                (TEXT("********* SDBusIssueRequest - MMC Status did not clear : 0x%08X \n"),
                (mmcStatus & 0x0000003F)));
        }
    
    }
#endif 
    DbgPrintZo(SDH_SEND_ZONE, (TEXT("SDBusIssueRequest - Request Sent\n")));

    return SD_API_STATUS_PENDING;
}
#define NUM_BYTE_FOR_FAST_PASS 0x1000
BOOL SDControllerISTHandler(PSDH_HARDWARE_CONTEXT pHCDevice, BOOL fTimeOut);
///////////////////////////////////////////////////////////////////////////////
//  SDHBusRequestHandler - bus request handler 
//  Input:  pHostContext - host controller context
//          Slot - slot the request is going on
//          pRequest - the request
//          
//  Output: 
//  Return: SD_API_STATUS Code
//  Notes:  The request passed in is marked as uncancelable, this function
//          has the option of making the outstanding request cancelable    
//          
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS SDHBusRequestHandler(PSDCARD_HC_CONTEXT pHCContext, 
                                     DWORD              Slot, 
                                     PSD_BUS_REQUEST    pRequest) 
{
    SD_API_STATUS status;
    PSDH_HARDWARE_CONTEXT      pController;     // our controller
    BOOL fHandled = FALSE;
    static  BOOL fIntrMasked = FALSE;	// flag to indicate if controller's interrupt is masked
    const TCHAR inData[] = TEXT("SDHBusRequestHandler IN");
    const TCHAR OutData[] = TEXT("SDHBusRequestHandler Out");
    DEBUGMSG(SDCARD_ZONE_FUNC,(TEXT("+SDHBusRequestHandler pRequest=%x"),pRequest));
        // get our extension 
    pController = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHCContext);
    ACQUIRE_LOCK(pController);
    if ( pController->pCurrentRequest) { // We have outstand request.
        ASSERT(FALSE);
        IndicateBusRequestComplete(pHCContext, pRequest, SD_API_STATUS_CANCELED);
        pController->pCurrentRequest = NULL;
    }
    pController->fCurrentRequestFastPath = FALSE;
    pController->pCurrentRequest = pRequest ;
    // initialize FastPathStatus per bus request to avoid last remained SD_API_STATUS_FAST_PATH_SUCCESS breaking the logic
    // pController->FastPathStatus = SD_API_STATUS_PENDING;

    if (pController->fFastPathEnabled &&
		pRequest->SystemFlags & SD_FAST_PATH_AVAILABLE && 
            !( SD_COMMAND != pRequest->TransferClass && 
                pRequest->NumBlocks * pRequest->BlockSize >=  pController->dwPollingModeSize)){   // We do fast path here.
        // if FAST PATH
        
        pController->fCurrentRequestFastPath = TRUE;
        InterruptMask(pController->dwSysintrSDMMC,TRUE);
        fIntrMasked = TRUE;		
        status = SDBusIssueRequest( pHCContext, Slot, pRequest );
        if( status == SD_API_STATUS_PENDING ) { // Polling for completion.
            while (pController->pCurrentRequest) {
                SDControllerISTHandler(pController, !(pController->DevicePresent));
                // jump out of this polling if it's non-fastpath (might be retried request)
                // SDControllerISTHandler is serving the interrupts as much as possible, it might delay to reach here!
                // if (FALSE == pController->fCurrentRequestFastPath) break;
				
            }               
            status = pController->FastPathStatus;
            if (status == SD_API_STATUS_SUCCESS) {
                status = SD_API_STATUS_FAST_PATH_SUCCESS;
            }
        }
        InterruptMask(pController->dwSysintrSDMMC,FALSE);
        // bus driver might exclude this bit while retrying the request		
       // ASSERT(pController->fCurrentRequestFastPath);

        fHandled = TRUE;
    }
    else {
        // normal path
        
        if ((fIntrMasked) && !(pController->fCurrentRequestFastPath)) {
            //unmask the interrupt if needed			
            InterruptMask(pController->dwSysintrSDMMC,FALSE);
            fIntrMasked = FALSE;		
        }
       pRequest->SystemFlags &= ~SD_FAST_PATH_AVAILABLE ;
       status = SDBusIssueRequest( pHCContext, Slot, pRequest );
    }
    RELEASE_LOCK(pController);
    DEBUGMSG(SDCARD_ZONE_FUNC,(TEXT("-SDHBusRequestHandler pRequest=%x"),pRequest));
    return status;
}
///////////////////////////////////////////////////////////////////////////////
//  SDHSlotOptionHandler - handler for slot option changes
//  Input:  pHostContext - host controller context
//          SlotNumber   - the slot the change is being applied to
//          Option       - the option code
//          pData        - data associated with the option
//          OptionSize   - size of option data
//  Output: 
//  Return: SD_API_STATUS code
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS SDHSlotOptionHandler(PSDCARD_HC_CONTEXT    pHCContext,
                                     DWORD                 SlotNumber, 
                                     SD_SLOT_OPTION_CODE   Option, 
                                     PVOID                 pData,
                                     ULONG                 OptionSize)
{
    SD_API_STATUS status = SD_API_STATUS_SUCCESS;   // status
    PSDH_HARDWARE_CONTEXT    pController;         // the controller
    PSD_HOST_BLOCK_CAPABILITY  pBlockCaps;          // queried block capabilities

        // get our extension 
    pController = GetExtensionFromHCDContext(PSDH_HARDWARE_CONTEXT, pHCContext);

    switch (Option) {

        case SDHCDSetSlotPower:
            DbgPrintZo(SDCARD_ZONE_INIT, 
                (TEXT("SDHSlotOptionHandler - called - SetSlotPower : 0x%08X  \r\n"), 
                *((PDWORD)pData)));
            break;

        case SDHCDSetSlotInterface:
            DbgPrintZo(SDCARD_ZONE_INIT, 
                (TEXT("SDHSlotOptionHandler - called - SetSlotInterface : Clock Setting: %d \r\n"), 
                ((PSD_CARD_INTERFACE)pData)->ClockRate));
            
            if (SD_INTERFACE_SD_MMC_1BIT == 
                ((PSD_CARD_INTERFACE)pData)->InterfaceMode) {
                DbgPrintZo(SDCARD_ZONE_INIT, 
                        (TEXT("SDHSlotOptionHandler - called - SetSlotInterface : setting for 1 bit mode \r\n")));
                pController->f4BitMode = FALSE;
            } else {
                DbgPrintZo(SDCARD_ZONE_INIT, 
                        (TEXT("SDHSlotOptionHandler - called - SetSlotInterface : setting for 4 bit mode \r\n")));
                pController->f4BitMode = TRUE;
            }
                // shut off clock first
            //SDClockOff(pController);
                // set rate
            SDSetRate(pController, &((PSD_CARD_INTERFACE)pData)->ClockRate);
            pController->dwWorkClkRate=pController->dwSDClockFrequency;

            break;

        case SDHCDEnableSDIOInterrupts:
            
            DbgPrintZo(SDCARD_ZONE_INIT, 
                (TEXT("SDHSlotOptionHandler - called - EnableSDIOInterrupts : on slot %d  \r\n"),
                SlotNumber));

            SDIO_INTERRUPT_ON(pController);
            pController->fSDIOEnabled = TRUE;

            break;

        case SDHCDAckSDIOInterrupt:

                // acquire the lock to block the SDIO interrupt thread
            ACQUIRE_LOCK(pController);

            if ( ( READ_MMC_REGISTER_DWORD( pController, MMC_STAT ) & 0x8000 ) &&
                 ( READ_MMC_REGISTER_DWORD( pController, MMC_IREG ) & 0x0800 ) &&
                 pController->fSDIOEnabled )
            {
                DbgPrintZo(/*SDCARD_ZONE_INIT*/SDH_INTERRUPT_ZONE, (TEXT("SDIO INT (still)!\r\n")));
                SDHCDIndicateSlotStateChange(pController->pHCContext, 
                                                0,
                                                DeviceInterrupting);
            }
            else if( pController->fSDIOEnabled )
            {
                SDIO_INTERRUPT_ON(pController);
            }

            RELEASE_LOCK(pController);

            break;

        case SDHCDDisableSDIOInterrupts:
            DbgPrintZo(SDCARD_ZONE_INIT, 
                (TEXT("SDHSlotOptionHandler - called - DisableSDIOInterrupts : on slot %d  \r\n"),
                SlotNumber));

            SDIO_INTERRUPT_OFF(pController);
            pController->fSDIOEnabled = FALSE;

            break;

        case SDHCDGetWriteProtectStatus:
            
            DbgPrintZo(SDCARD_ZONE_INIT, 
                (TEXT("SDHSlotOptionHandler - called - SDHCDGetWriteProtectStatus : on slot %d  \r\n"),
                 SlotNumber)); 
            
            if( IsCardWriteProtected(pController) ) {
                ((PSD_CARD_INTERFACE)pData)->WriteProtected = TRUE;
                DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDHSlotOptionHandler - Card is write protected \r\n"))); 
            } else {
                ((PSD_CARD_INTERFACE)pData)->WriteProtected = FALSE;
                DbgPrintZo(SDCARD_ZONE_INIT, (TEXT("SDHSlotOptionHandler - Card is write enabled \r\n"))); 
            }

            break;

         case SDHCDQueryBlockCapability:
            pBlockCaps = (PSD_HOST_BLOCK_CAPABILITY)pData;

             DbgPrintZo(SDCARD_ZONE_INIT, 
             (TEXT("SDHSlotOptionHandler: Read Block Length: %d , Read Blocks: %d\r\n"), 
                pBlockCaps->ReadBlockSize, 
                pBlockCaps->ReadBlocks));
             DbgPrintZo(SDCARD_ZONE_INIT, 
             (TEXT("SDHSlotOptionHandler: Write Block Length: %d , Write Blocks: %d\r\n"), 
                pBlockCaps->WriteBlockSize, 
                pBlockCaps->WriteBlocks));

                // the PXA controller can only handle up to 1024 bytes
                // with a minimum of 32 bytes per transfer
            if (pBlockCaps->ReadBlockSize > SDH_MAX_BLOCK_SIZE) {
                pBlockCaps->ReadBlockSize = SDH_MAX_BLOCK_SIZE;
            }

            if (pBlockCaps->ReadBlockSize < SDH_MIN_BLOCK_SIZE ) {
                pBlockCaps->ReadBlockSize = SDH_MIN_BLOCK_SIZE;
            }

            if (pBlockCaps->WriteBlockSize > SDH_MAX_BLOCK_SIZE) {
                pBlockCaps->WriteBlockSize = SDH_MAX_BLOCK_SIZE;
            }
            
            if (pBlockCaps->WriteBlockSize < SDH_MIN_BLOCK_SIZE ) {
                pBlockCaps->WriteBlockSize = SDH_MIN_BLOCK_SIZE;
            }

                // the PXA controller can handle 64K blocks,
                // we leave the number of blocks alone
             
            break;

        case SDHCDGetSlotInfo:
            if( OptionSize != sizeof(SDCARD_HC_SLOT_INFO) || pData == NULL )
            {
                status = SD_API_STATUS_INVALID_PARAMETER;
            }
            else
            {
                PSDCARD_HC_SLOT_INFO pSlotInfo = (PSDCARD_HC_SLOT_INFO)pData;

                // set the slot capabilities
                SDHCDSetSlotCapabilities(pSlotInfo, SD_SLOT_SD_1BIT_CAPABLE | 
                                                    SD_SLOT_SD_4BIT_CAPABLE |
                                                    SD_SLOT_SDIO_CAPABLE);

                SDHCDSetVoltageWindowMask(pSlotInfo, (SD_VDD_WINDOW_3_2_TO_3_3 | SD_VDD_WINDOW_3_3_TO_3_4)); 

                // Set optimal voltage
                SDHCDSetDesiredSlotVoltage(pSlotInfo, SD_VDD_WINDOW_3_2_TO_3_3);

                SDHCDSetMaxClockRate(pSlotInfo, pController->dwMaximumSDClockFrequency);

                // Set power up delay. We handle this in SetVoltage().
                SDHCDSetPowerUpDelay(pSlotInfo, 300);
            }
            break;

        default:
           status = SD_API_STATUS_INVALID_PARAMETER;

    }

    return status;
}

///////////////////////////////////////////////////////////////////////////////
//  HandleProgramDone - Handle program done interrupt
//  Input:  pController - the controller that is interrupting
//  Output: 
//  Return:
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
VOID HandleProgramDone(PSDH_HARDWARE_CONTEXT pController)
{
    PSD_BUS_REQUEST pRequest;       // current request

    PROGRAM_DONE_INTERRUPT_OFF(pController);

        // get the current request  
    pRequest = pController->pCurrentRequest;

        // this should never happen because we mark the request as un-cancelable.
    DEBUG_ASSERT(NULL != pRequest);
    if(NULL == pRequest)
    {
        return;
    }

    SetCurrentState(pController, WriteDataDone);
    RETAILMSG(SDDEBUG,(TEXT("[SDH] SetCurrentState-WriteDataDone\r\n")));

        // notice there is no status to check for a programming error
        // this is up to the upper level drivers to send a card status command
    DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("HandleProgramDone: Programming Complete \r\n")));

    DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleProgramDone reports Bus Request Succeeded\r\n")));

    IndicateBusRequestComplete(pController->pHCContext,
                                    pRequest ,
                                    SD_API_STATUS_SUCCESS);
}

///////////////////////////////////////////////////////////////////////////////
//  EmptyReceiveFifo - Empty the receive Fifo
//  Input:  pController - the controller instance
//          pRequest - the request to get the data from
//          ByteCount - number of bytes to read
//          MaxBytes - limit of this transfer
//  Output: 
//  Return:
//  Notes:  
//      
///////////////////////////////////////////////////////////////////////////////
VOID EmptyReceiveFifo(PSDH_HARDWARE_CONTEXT pController, 
                      PSD_BUS_REQUEST         pRequest,
                      ULONG                   ByteCount,
                      ULONG                   MaxBytes)
{   
    DWORD dwTmp;
    ULONG   receiveBufferIndex = 0; // receive buffer index

    volatile UCHAR *pMMC_RX_Fifo = (volatile UCHAR *)&(pController->pSDMMCRegisters->rxfifo);

        // we are touching the block buffer, we must set the process permissions
    SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {

            // empty the FIFO
        while (ByteCount) {
            if( !(pController->DevicePresent) )
            {
                DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("EmptyReceiveFifo: Card ejected!\r\n")));     
                break;
            }

            dwTmp = pController->pSDMMCRegisters->ireg;

                // fill up the receive buffer
            if (receiveBufferIndex < MMC_RXFIFO_SIZE) {

                    // read in the byte from the FIFO
                pController->RcvBuffer[receiveBufferIndex] = *pMMC_RX_Fifo;

                receiveBufferIndex++;
                ByteCount--;

                    // check to see if we've read enough
                if ((pRequest->HCParam + receiveBufferIndex) >= MaxBytes) {
                    break;
                }

            } else {

                    // receive buffer is full, now transfer the data safely
                SDPerformSafeCopy(&pRequest->pBlockBuffer[pRequest->HCParam],
                                  pController->RcvBuffer,
                                  receiveBufferIndex);
                    // bump the running count
                pRequest->HCParam += receiveBufferIndex;
                    // reset receive buffer index
                receiveBufferIndex = 0;
            }
              
        } // while

            // check for any left over data
        if (receiveBufferIndex) {
                // safely copy the data
            SDPerformSafeCopy(&pRequest->pBlockBuffer[pRequest->HCParam],
                              pController->RcvBuffer,
                              receiveBufferIndex);
                // bump the running count
            pRequest->HCParam += receiveBufferIndex;
        }

    } SD_RESTORE_PROC_PERMISSIONS();

}

///////////////////////////////////////////////////////////////////////////////
//  HandleTransferDone- Handle transfer done interrupt 
//  Input:  pController - the controller that is interrupting
//          fForceTimeout - if true, we reached a timeout during transfer
//  Output: 
//  Return:
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
VOID HandleTransferDone(PSDH_HARDWARE_CONTEXT pController, BOOL fForceTimeout)
{
    PSD_BUS_REQUEST pRequest;       // current request
    DWORD           regValue;       // intermediate byte value
    ULONG           maxBytes;       // max bytes

        // turn off the transfer done interrupt
    TRANSFER_DONE_INTERRUPT_OFF(pController);
      
        // get the current request  
    pRequest = pController->pCurrentRequest; 

        // this should never happen because we mark the request as un-cancelable
    DEBUG_ASSERT(NULL != pRequest);
    if( !pRequest ) 
    {
        RX_FIFO_INTERRUPT_OFF(pController);
        TX_FIFO_INTERRUPT_OFF(pController);
        return;
    }

    if (TRANSFER_IS_READ(pRequest)) {
            // make sure RX fifo interrupt is off 
		//NKDbgPrintfW(TEXT("Trans Done..Rcv_OK.\r\n"));
#ifndef DMA_TEST_MODE
        RX_FIFO_INTERRUPT_OFF(pController);
#endif
    } else if (TRANSFER_IS_WRITE(pRequest)) {
            // make sure TX fifo interrupt is off 
		//NKDbgPrintfW(TEXT("Trans Done..Xmt_OK.\r\n"));
#ifndef DMA_TEST_MODE
        TX_FIFO_INTERRUPT_OFF(pController);
#endif
            // can't turn off the clock until the prog done interrupt!
    } else {
        DEBUG_ASSERT(FALSE);
    }

        // check the transfer status
    regValue = READ_MMC_REGISTER_DWORD(pController, MMC_STAT);
	
        // check for errors
    if (regValue & MMC_STAT_FLASH_ERROR) {
        ASSERT(0);

        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDone reports FLASH ERROR\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_DATA_ERROR);
        return;
		
    }

    if (regValue & MMC_STAT_SPI_WR_ERROR) {
        ASSERT(0);
    }

    if (regValue & MMC_STAT_RD_STALLED) {
        ASSERT(0);
    }

    if ( ( regValue & MMC_STAT_READ_TIMEOUT ) || fForceTimeout ) {
        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDoneInterrupt: Read Data TimedOut \n")));     

        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports DATA TIMEOUT\r\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_DATA_TIMEOUT);
        return;

    } else if (regValue & MMC_STAT_READ_DATA_CRC_ERROR) {

        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDoneInterrupt: Read Data Contains CRC error \r\n"))); 
        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports CRC ERROR\r\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_CRC_ERROR);
        return;
    } else if (regValue & MMC_STAT_WRITE_DATA_CRC_ERROR) {

        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDoneInterrupt: Card received Write Data with CRC error \r\n"))); 
        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports CRC ERROR\r\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_CRC_ERROR);
        return;
    }

    
    if (TRANSFER_IS_READ(pRequest)) {
            // why are we doing this here? If the remaining read data is less than a Fifo's worth (32)
            // we won't get the RX Fifo Read Request interrupt because the fifo won't be full.
            // also even if it is full or if this isn't the case the TRANSFER_DONE bit seems to mask it out
            // anyways this prevents the problem where there are bytes stuck in the Fifo
        maxBytes = pRequest->NumBlocks * pRequest->BlockSize;

#ifdef DMA_TEST_MODE
	     if (FALSE) {							// Skip. NO need to empty RCV Fifo. Stop.
#else
        if (pRequest->HCParam < maxBytes) {
#endif
            DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleTransferDoneInterrupt: Fifo contains remaining data, Max: %d, current count %d  \r\n"),
                maxBytes, pRequest->HCParam));
                // get the remaining bytes out of the FIFO
            EmptyReceiveFifo(pController, 
                             pRequest, 
                             (maxBytes - pRequest->HCParam), 
                             maxBytes);
        }

        SetCurrentState(pController, ReadDataDone);
        RETAILMSG(SDDEBUG,(TEXT("[SDH] SetCurrentState-ReadDataDone\r\n")));

        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Bytes read: [%S]\r\n"), HexDisplay(pRequest, pRequest->pBlockBuffer, TRANSFER_SIZE(pRequest) ) ) );
    }


    if (TRANSFER_IS_WRITE(pRequest)) {

        if (!IS_PROGRAM_DONE(pController)) {
            SetCurrentState(pController, ProgramWait);
            RETAILMSG(SDDEBUG, (TEXT("[SDH] SetCurrentState-ProgramWait\r\n")));
 
                // turn on programming done interrupt
            PROGRAM_DONE_INTERRUPT_ON(pController); 
            //Sleep(500);

                // check to see if programming is finished
            if (!IS_PROGRAM_DONE(pController)) {
                DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("HandleTransferDoneInterrupt: Programming Not Complete \r\n")));   
            }

            // if we wait on the programming done interrupt this could
            // go on forever because now it is up to the memory card, 
            // we may have to make this request cancelable at this point
            
            return;
        }
    } 

    DEBUG_ASSERT((pRequest->HCParam >= (pRequest->NumBlocks * pRequest->BlockSize)));
        // complete the request
    DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports Data Transfer Completed\r\n")));
    if (TRANSFER_IS_READ(pRequest)) {
		DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Bytes read: [%S]\r\n"), HexDisplay(pRequest, pRequest->pBlockBuffer, TRANSFER_SIZE(pRequest) ) ) );
	}

    IndicateBusRequestComplete(pController->pHCContext,
                                    pRequest ,
                                    SD_API_STATUS_SUCCESS);
}


///////////////////////////////////////////////////////////////////////////////
//  SDLoadXmitFifo - load the transmit fifo
//  Input:  pController - the controler
//          pRequest    - the request 
//  Output: 
//  Return:  returns TRUE if the request has been fullfilled
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
BOOL SDLoadXmitFifo(PSDH_HARDWARE_CONTEXT pController, PSD_BUS_REQUEST pRequest)
{
    DWORD           maxBytes;       // max bytes
#ifndef DMA_TEST_MODE
    ULONG           ii = 0;         // loop variable
    ULONG           remainingBytes; // remaining bytes in the transfer
    volatile UCHAR *pMMC_TX_Fifo = (volatile UCHAR *)&(pController->pSDMMCRegisters->txfifo);
#else
    PSDHCDmacDescriptor pSDHCDmacDscr=(PSDHCDmacDescriptor)pController->DmacDscr;
    NextXRBuffers * NextTransfer=pSDHCDmacDscr->NextTransfer;
    ULONG i_NT=pSDHCDmacDscr->i_NT;
#endif

        // precalc
    maxBytes = pRequest->NumBlocks * pRequest->BlockSize;

#ifndef DMA_TEST_MODE
	// Done if no more data to transmit.
    if (pRequest->HCParam >= maxBytes) {
        return TRUE;
    } 
#endif

    DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("SDLoadXmitFifo: Current %d \r\n"),pRequest->HCParam));

        // make sure the partial full flag is cleared
    TX_BUFFER_PARTIAL_NOT_FULL(pController);

#ifndef DMA_TEST_MODE
        // according to the spec the TX Fifo Empty interrupt asserts once when the fifo is
        // empty 
    if ((maxBytes - pRequest->HCParam) >= (LONG)MMC_TXFIFO_SIZE) {
            // because the remaining bytes is greater than or equal to the fifo size,
            // the Tx Fifo better be empty according to Intel's spec!
        // DEBUG_ASSERT(TX_FIFO_EMPTY(pController)); @
    }

        // we are touching the block buffer, we must set the process permissions
    SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {

            // figure out how much to prefetch from the user
            // buffer safely
        remainingBytes = maxBytes - pRequest->HCParam;

        if (remainingBytes > MMC_TXFIFO_SIZE) {
                // fix it
            remainingBytes = MMC_TXFIFO_SIZE;
        } 

            // perform the safe copy
        SDPerformSafeCopy(pController->XmitBuffer,
                          &pRequest->pBlockBuffer[pRequest->HCParam],
                          remainingBytes);            

            // according to the spec (15.2.8.3) the TX Fifo interrupt asserts for every empty fifo
            // (32 bytes)
            // so we write a Fifo's worth, as per spec 
        for (ii = 0; ii < remainingBytes; ii++) {
            
            if( !(pController->DevicePresent) )
            {
                DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("SDLoadXmitFifo: Card ejected!\r\n")));     
                break;
            }

                // transfer bytes to the fifo from the safe buffer
            *pMMC_TX_Fifo = pController->XmitBuffer[ii];

            pRequest->HCParam++;

                // check to see if we've read enough
            if (pRequest->HCParam >= maxBytes) {
                break;
            }
        }

    } SD_RESTORE_PROC_PERMISSIONS();

        // check for a partial buffer
    if (ii < MMC_TXFIFO_SIZE) {
        TX_BUFFER_PARTIAL_FULL(pController);
    }

    DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("SDLoadXmitFifo: New Current %d  \r\n"),pRequest->HCParam));
    
        // see if we are done
    if (pRequest->HCParam >= maxBytes) {
        return TRUE;
    } 

    return FALSE;

#endif

#ifdef DMA_TEST_MODE
///*** Start DMA

    // Wait for previous XMT operation to finish.
    if(  WAIT_TIMEOUT == WaitForSingleObject(pSDHCDmacDscr->DMATxEventHandle, 15000))
    {
            NKDbgPrintfW(TEXT("[MMC] XmtChannel Timed OUT...\r\n"));
    }
            //NKDbgPrintfW(TEXT("WaitFor-1..Xmt_OK.\r\n"));

    // Continue to Xmt until all the data in the bus request packet has been sent.

    while ( NextTransfer[++i_NT%2].MoreDataToTransfer )
    {  // Start Transfer of previously prepared descriptors/buffers.
        XllpDmacCfgChannelDescTransfer(
                                 pSDHCDmacDscr->pDMACHandle,     			
                                 NextTransfer[i_NT%2].pPhysDescriptor,
                                 pSDHCDmacDscr->XmtChannel,
                                 pSDHCDmacDscr->txChannel);
        XllpDmacStartTransfer(pSDHCDmacDscr->pDMACHandle, pSDHCDmacDscr->XmtChannel );
        // Create Descriptors for the next buffer. A length (count) of zero is OK.
        if( (maxBytes - pRequest->HCParam) > TRANSFER_BUF_SIZE/2 )
        {  // Transfer another PAGE from the Request buffer.
            NextTransfer[(i_NT+1)%2].Length  = TRANSFER_BUF_SIZE/2;
        }
        else  // It all fits in this last buffer.
        {
            NextTransfer[(i_NT+1)%2].Length              = maxBytes - pRequest->HCParam;
            if( 0 == NextTransfer[(i_NT+1)%2].Length)
            {
                NextTransfer[(i_NT+1)%2].MoreDataToTransfer = FALSE;
            }
        }

        // Fill the next transfer buffer.

        // we are touching the block buffer, we must set the process permissions
        SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {

        memcpy( NextTransfer[(i_NT+1)%2].pStartVirtDataBuffer, 
                &pRequest->pBlockBuffer[pRequest->HCParam], NextTransfer[(i_NT+1)%2].Length );

        } SD_RESTORE_PROC_PERMISSIONS();


        pRequest->HCParam   += NextTransfer[(i_NT+1)%2].Length;
        
        // Create the next descriptor chain.

        CreateSDIODescChainXR(
       	                pController,
                        NextTransfer[(i_NT+1)%2].pVirtDescriptor, 
                        NextTransfer[(i_NT+1)%2].pPhysDescriptor, 
                        NextTransfer[(i_NT+1)%2].pStartPhysDataBuffer, 
                        NextTransfer[(i_NT+1)%2].Length,
                        XMT_SDIO);
        
        //  The previous Xmt descriptors/buffer transfer
        //     needs to complete before more can be done.
        if(  WAIT_TIMEOUT == WaitForSingleObject(pSDHCDmacDscr->DMATxEventHandle, 15000))
        {
                NKDbgPrintfW(TEXT("[MMC] XmtChannel Timed OUT...\r\n"));
        }
        //NKDbgPrintfW(TEXT("WaitFor-2..Xmt_OK.\r\n"));
    }

    TX_BUFFER_PARTIAL_FULL(pController);  // Flush TxFifo. Not always needed, but no harm is done.

    // Exit. Indicate all blocks succesfully transfered.
    pRequest->HCParam = maxBytes;

#if(CEATA_CCS_MODE)
{
	DWORD waitStatus;
	//CEATA : wait for CCS interrupt	
	if((pRequest->CommandCode== 61)&& (TRUE==SDHCISFORCEATA(pController))
	{
		//wait for CEATA CCS from GPIO input
		XllpGpioGetEdgeDetectStatus((pController->XllpMMCContext).pGPIOReg, XLLP_GPIO_MMC_CMD_0, &CCSStatus);
		if(CCSStatus)
		{
			XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
			RETAILMSG(1, (TEXT("CEATA CCS received CCS -1,wait event SUCCESS, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));			
		}
		else
		{
			waitStatus = WaitForSingleObject(hCEATACCSIntrEvent, 5000);
			 switch (waitStatus)
		        {
		        case WAIT_OBJECT_0:
			     XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
		            RETAILMSG(1, (TEXT("CEATA CCS received CCS -2, wait event SUCCESS, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));
		            break;
		        case WAIT_TIMEOUT:
				XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
				//send CCSD
				XllpMMCSendCEATACCSD(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
				RETAILMSG(1, (TEXT("CEATA CCS: wait event, returns TIMEOUT, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0)); 
		            break;
		        default:
				XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
				//send CCSD
				XllpMMCSendCEATACCSD(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
		            RETAILMSG(1, (TEXT("CEATA CCS: wait event, returns ERROR=%x \r\n"), GetLastError())); 
		            break;
		        }
		}
		RETAILMSG(1, (TEXT("CEATA enable CCS, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));
		RETAILMSG(1, (TEXT("CEATA enable CCS, gfer0=%x\r\n"),pController->pGPIORegisters->gfer0));
		RETAILMSG(1, (TEXT("CEATA enable CCS, gsfer0=%x\r\n"),pController->pGPIORegisters->gsfer0));
		ResetEvent(hCEATACCSIntrEvent);
		InterruptDone(SYSINTR_CEATACCS);
	}
}
#endif

    return TRUE;

#endif

}


///////////////////////////////////////////////////////////////////////////////
//  HandleXmitInterrupt - handle the Xmit Fifo Empty interrupt
//  Input:  pController - the controler
//  Output: 
//  Return:
//  Notes:   
///////////////////////////////////////////////////////////////////////////////
VOID HandleXmitInterrupt(PSDH_HARDWARE_CONTEXT pController)
{
    PSD_BUS_REQUEST pRequest;       // current request
  
        // get the current request  
    pRequest = SDHCDGetAndLockCurrentRequest(pController->pHCContext, 0);

        // this should never happen because we mark the request as un-cancelable
    DEBUG_ASSERT(NULL != pRequest);

    if (SDLoadXmitFifo(pController, pRequest)) {
            // the request is complete  
            // turn off the Fifo Interrupts
        TX_FIFO_INTERRUPT_OFF(pController);
        SetCurrentState(pController, WriteDataTransferDone);
        RETAILMSG(SDDEBUG,(TEXT("[SDH] SetCurrentState-WriteDataTransferDone\r\n")));

    }

    // now we need to wait for the controller to transmit (transfer done) and the card 
    // to complete programming (program done)
    // if the transfer is done or programming is done before we go back into the interrupt wait
    // the interrupt bit will be set and the IST loop will handle the transfer done in this same thread     

}

///////////////////////////////////////////////////////////////////////////////
//  HandleReceiveInterrupt - Handle recieve data interrupt
//  Input:  pController - the controller that is interrupting
//  Output: 
//  Return:
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
VOID HandleReceiveInterrupt(PSDH_HARDWARE_CONTEXT pController)
{
    PSD_BUS_REQUEST pRequest;       // current request
    DWORD           maxBytes;       // max bytes
    ULONG           ii = 0;         // loop variable

        // get the current request  
    pRequest = SDHCDGetAndLockCurrentRequest(pController->pHCContext, 0);

        // this should never happen because we mark the request as un-cancelable
    DEBUG_ASSERT(NULL != pRequest);

    maxBytes = pRequest->NumBlocks * pRequest->BlockSize;
    
    DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleReceiveInterrupt: Max: %d, Current %d \r\n"),
        maxBytes, pRequest->HCParam));
 
        // according to the spec (15.2.8.2) the RX Fifo interrupt asserts for every 32 bytes and
        // remains asserted until the RX fifo is empty, once it is empty 
        // the interrupt req resets and won't assert until 32 more bytes are received
        // or until the transfer is complete and their is a partial Fifo
    if ((maxBytes - pRequest->HCParam) >= (LONG)MMC_RXFIFO_SIZE) {
            // because the remaining bytes is greater than or equal to the fifo size,
            // the fifo better be full as per Intel spec!
        // DEBUG_ASSERT(RX_FIFO_FULL(pController)); @
    }

        // read a Fifo's worth, as per spec 
    EmptyReceiveFifo(pController, pRequest, MMC_RXFIFO_SIZE, maxBytes);

    DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleReceiveInterrupt: New Current %d  \r\n"),pRequest->HCParam));
    
        // see if we are done
    if (pRequest->HCParam >= maxBytes) {
        DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleReceiveInterrupt: Data Transfer Completing waiting for TRANS_DONE..\r\n")));    
            // if we are finished, turn off the RX Fifo request interrupt
        RX_FIFO_INTERRUPT_OFF(pController);  
        SetCurrentState(pController, ReadDataTransferDone);
        RETAILMSG(SDDEBUG,(TEXT("[SDH] SetCurrentState-ReadDataTransferDone\r\n")));

        // now we need to wait for the controller to perform the CRC check and issue trailing clocks (transfer done)
        // if the transfer is done, the interrupt bit will be set and the IST loop will 
        // handle the transfer done in this same thread      
    }  

        // we could mark the request as cancelable again...
}

///////////////////////////////////////////////////////////////////////////////
//  HandleEndCommandInterrupt - Handle End of Command Interrupt
//  Input:  pController - the controller that is interrupting
//  Output: 
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
VOID HandleEndCommandInterrupt(PSDH_HARDWARE_CONTEXT pController)
{
    DWORD               statRegister;   // status register
    PSD_BUS_REQUEST     pRequest;       // the request to complete
    DWORD               regValue;       // intermediate reg value
    LONG                ii;             // loop variable  
    LONG                startingOffset;     // starting offset in response buffer
    USHORT              responseBuffer[SDH_RESPONSE_FIFO_DEPTH]; // response buffer

#ifdef DMA_TEST_MODE
// Local Variables
    DWORD           maxBytes;       // maximum number bytes requested.
    PSDHCDmacDescriptor pSDHCDmacDscr=pController->DmacDscr;
    ULONG i_NT=pSDHCDmacDscr->i_NT;
    NextXRBuffers * NextTransfer=pSDHCDmacDscr->NextTransfer;
#endif


        // get the current request  
    pRequest = pController->pCurrentRequest;

        // this should never happen because we mark the request as un-cancelable
    DEBUG_ASSERT(NULL != pRequest);
    if( pRequest == NULL )
    {
        END_CMD_INTERRUPT_OFF(pController);
        return;
    }

        // get the stat register
    statRegister = READ_MMC_REGISTER_DWORD(pController, MMC_STAT);

        // mask the END_CMD interrupt, the command is complete , however
        // reading the STAT register doesn't clear the interrupt
        // we need to just mask this interrupt out
    END_CMD_INTERRUPT_OFF(pController);
		
 #if(CEATA_CCS_MODE)	
	//CEATA TODO: turn on CCS interrupt, even before checking for error to make sure capture CCS signal
    if((pRequest->CommandCode== 61)&& (TRUE==SDHCISFORCEATA(pController))
    {
        XllpMMCEnableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
        XllpGpioSetDirection((pController->XllpMMCContext).pGPIOReg, XLLP_GPIO_MMC_CMD_0, XLLP_GPIO_DIRECTION_IN);    
        RETAILMSG(1, (TEXT("CEATA enable CCS, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));
        RETAILMSG(1, (TEXT("CEATA enable CCS, gfer0=%x\r\n"),pController->pGPIORegisters->gfer0));
        RETAILMSG(1, (TEXT("CEATA enable CCS, gsfer0=%x\r\n"),pController->pGPIORegisters->gsfer0));
        RETAILMSG(1, (TEXT("CEATA enable CCS, gpdr0=%x\r\n"),pController->pGPIORegisters->gpdr0));
    }
#endif         

    if (statRegister & MMC_STAT_FLASH_ERROR) {
        ASSERT(0);

        regValue = READ_MMC_REGISTER_DWORD(pController, MMC_CMD);
        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleEndCommandInterrupt: response for command %d , FLASH ERROR \n"),regValue));

            // complete the current request with a timeout
        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt reports FLASH ERROR\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_UNSUCCESSFUL);
        return;
		
    }

    if (statRegister & MMC_STAT_SPI_WR_ERROR) {
        ASSERT(0);
    }

    if (statRegister & MMC_STAT_RD_STALLED) {
        ASSERT(0);
    }

    if (statRegister & MMC_STAT_RESPONSE_TIMEOUT) {
        regValue = READ_MMC_REGISTER_DWORD(pController, MMC_CMD);
        regValue &= 0x3F;
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("HandleEndCommandInterrupt: response for command %d , timed - out \r\n"),regValue));

        RETAILMSG(SDDEBUG, (TEXT("[%s] HandleEndCommandInterrupt(TIMEOUT): response for command %d , timed - out \r\n"),pController->szName, regValue));

            // complete the current request with a timeout
        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt reports RESPONSE TIMEOUT\r\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_RESPONSE_TIMEOUT);
#if(CEATA_CCS_MODE)
        if((pRequest->CommandCode== 61)&& (TRUE==SDHCISFORCEATA(pController))
        {
            XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
            XllpMMCSendCEATACCSD(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
            ResetEvent(hCEATACCSIntrEvent);
            InterruptDone(SYSINTR_CEATACCS);
        }
#endif	
        return;
    }

    if (statRegister & MMC_STAT_RESPONSE_CRC_ERROR) {
        regValue = READ_MMC_REGISTER_DWORD(pController, MMC_CMD);
        regValue &= 0x3F;
        RETAILMSG(SDDEBUG, (TEXT("[%s] HandleEndCommandInterrupt(ERROR): response for command %d , timed - out \r\n"), pController->szName, regValue));		
        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleEndCommandInterrupt: response for command %d , contains a CRC error \r\n"), regValue));
            // complete the current request with a CRC error status
        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt reports CRC ERROR\r\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_CRC_ERROR);
#if(CEATA_CCS_MODE)
        if((pRequest->CommandCode== 61)&& (TRUE==SDHCISFORCEATA(pController))
        {
            XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
            XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
            ResetEvent(hCEATACCSIntrEvent);
            InterruptDone(SYSINTR_CEATACCS);
        }
#endif		
        return;
    }

   
    if (NoResponse == pRequest->CommandResponse.ResponseType) {
        startingOffset = -1;
    } else if (ResponseR2 == pRequest->CommandResponse.ResponseType) {
            // 8 words - 128 bits
        startingOffset = SDH_RESPONSE_FIFO_DEPTH - 1;
    } else {
            // 3 WORDS - 48 bits
        startingOffset = 2;
    }

    RETAILMSG(SDDEBUG, (TEXT("[%s] HandleEndCommandInterrupt(SUCCESS) \r\n"), pController->szName));


    if (NoResponse != pRequest->CommandResponse.ResponseType) {

            // read in the response words from the response fifo.
        for (ii = startingOffset; ii >= 0; ii--) {
                // read from the fifo
            responseBuffer[ii] = (USHORT)(READ_MMC_REGISTER_DWORD(pController, MMC_RES));
        }

         
        if (ResponseR2 == pRequest->CommandResponse.ResponseType)  {
                // since the response Fifo is only 16 bytes, the R2 response which is normally 17 bytes
                // gets crammed into 16 bits, this offset the whole R2 response by 1 byte so when
                // copy the data to the response buffer, bump over the place holder for the CRC
            memcpy(&pRequest->CommandResponse.ResponseBuffer[1], 
                   responseBuffer, 
                   (sizeof(USHORT)) * (startingOffset + 1));
        } else {
                // all other responses are nicely aligned to 6 bytes, the CRC value in the last 
                // dword is not set, but we copy it anyways to the response buffer
            memcpy(pRequest->CommandResponse.ResponseBuffer, 
                   responseBuffer, 
                   (sizeof(USHORT)) * (startingOffset + 1));
        }
    }


        // check for command/response only
    if (SD_COMMAND == pRequest->TransferClass) {

            // check to see if this request was a response with busy
        if (ResponseR1b == pRequest->CommandResponse.ResponseType) { 

            while( ( !( statRegister & MMC_STAT_PROGRAM_DONE ) ) &&
                   ( !( pController->DriverShutdown ) ) &&
                   pController->DevicePresent )
            {
                statRegister = READ_MMC_REGISTER_DWORD(pController, MMC_STAT);
            }
        }

        SetCurrentState(pController, CommandComplete);
        RETAILMSG(SDDEBUG,(TEXT("[%s] SetCurrentState-CommandComplete\r\n"), pController->szName));

        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt reports Bus Request Completed\r\n")));
        IndicateBusRequestComplete(pController->pHCContext,
                                        pRequest ,
                                        SD_API_STATUS_SUCCESS);    
    } else {
          
        if (TRANSFER_IS_READ(pRequest)){   
            DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt starting READ TRANSFER of %d blocks of %d bytes\r\n"), pRequest->NumBlocks, pRequest->BlockSize ));
                // turn on RX Fifo interrupts
#ifndef DMA_TEST_MODE
            RX_FIFO_INTERRUPT_ON(pController);
#endif
            SetCurrentState(pController, ReadDataTransfer);
            RETAILMSG(SDDEBUG,(TEXT("[%s] SetCurrentState-ReadDataTransfer\r\n"), pController->szName));


#ifdef DMA_TEST_MODE
		
            // Wait for the first RCV operation to finish.
            if(  WAIT_TIMEOUT == WaitForSingleObject(pSDHCDmacDscr->DMARxEventHandle, 15000))
            {
                NKDbgPrintfW(TEXT("[%s] RcvChannel Timed OUT...\r\n"), pController->szName);
            }
            //NKDbgPrintfW(TEXT("WaitFor-1..Rcv_OK.\r\n"));

            // Block buffer may be in another process, so get permission to read/write that memory.
        SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {
    
            maxBytes = pRequest->NumBlocks * pRequest->BlockSize;

            // Move data to Bus Request buffer.
            memcpy( &pRequest->pBlockBuffer[pRequest->HCParam], NextTransfer[i_NT%2].pStartVirtDataBuffer, 
                     NextTransfer[i_NT%2].Length );
            // Remember where in the Request buffer to write the next data.
            pRequest->HCParam += NextTransfer[i_NT%2].Length;


            // Continue to Rcv until the bus request buffer is full.

            while ( NextTransfer[++i_NT%2].MoreDataToTransfer )
            {  // Start Rcv of previously prepared descriptors/buffers.
                XllpDmacCfgChannelDescTransfer(
                                    pSDHCDmacDscr->pDMACHandle,
                                    NextTransfer[i_NT%2].pPhysDescriptor,
                                    pSDHCDmacDscr->RcvChannel,
                                    pSDHCDmacDscr->rxChannel);
                XllpDmacStartTransfer( pSDHCDmacDscr->pDMACHandle, pSDHCDmacDscr->RcvChannel );
                // Create Descriptors for the next buffer.
                if( (maxBytes - pSDHCDmacDscr->CommittedToRcvNT) > TRANSFER_BUF_SIZE/2 )
                {  // Transfer another Buffer to the Request buffer.
                    NextTransfer[(i_NT+1)%2].Length  = TRANSFER_BUF_SIZE/2;
                }
                else  // It all fits in this last buffer.
                {
                    NextTransfer[(i_NT+1)%2].Length              = maxBytes - pSDHCDmacDscr->CommittedToRcvNT;
                    if( 0 == NextTransfer[(i_NT+1)%2].Length)
                    {
                        NextTransfer[(i_NT+1)%2].MoreDataToTransfer = FALSE;
                    }
                }
            
                // Create the next descriptor chain.

                CreateSDIODescChainXR(
                            pController,
                            NextTransfer[(i_NT+1)%2].pVirtDescriptor, 
                            NextTransfer[(i_NT+1)%2].pPhysDescriptor, 
                            NextTransfer[(i_NT+1)%2].pStartPhysDataBuffer, 
                            NextTransfer[(i_NT+1)%2].Length,
                            RCV_SDIO);

                // Count the number of bytes for which DMA descriptors are committed. 

                pSDHCDmacDscr->CommittedToRcvNT += NextTransfer[(i_NT+1)%2].Length;

        
                //  Previously started descriptor/buffer Rcv operation
                //     needs to complete before more can be done.
                if(  WAIT_TIMEOUT == WaitForSingleObject(pSDHCDmacDscr->DMARxEventHandle, 15000))
                {
                    NKDbgPrintfW(TEXT("[MMC] RcvChannel Timed OUT...\r\n"));
                }
                //NKDbgPrintfW(TEXT("WaitFor-2..Rcv_OK.\r\n"));

                // Move Rcv data to Bus Request buffer.

                memcpy( &pRequest->pBlockBuffer[pRequest->HCParam], NextTransfer[i_NT%2].pStartVirtDataBuffer, 
                        NextTransfer[i_NT%2].Length );
                // Remember where in the Request buffer to write the next data.
                pRequest->HCParam += NextTransfer[i_NT%2].Length;
            }

        } SD_RESTORE_PROC_PERMISSIONS();

            // Buffers may be too small.
            if(!(READ_MMC_REGISTER_DWORD(pController, MMC_IREG) & MMC_IREG_DATA_TRAN_DONE))
            {
                //--NKDbgPrintfW(TEXT("NO DATA_TRAN_DONE after DMA.\r\n"));
            }                  

            
            // Indicate all blocks succesfully transfered.
            pRequest->HCParam = pRequest->NumBlocks * pRequest->BlockSize;

#endif

                // turn on the transfer done interrupt to check for timeout on reads
                // the receive handler will turn this off after getting the first byte
            TRANSFER_DONE_INTERRUPT_ON(pController);
#if(CEATA_CCS_MODE)
            //CEATA: wait for CCS interrupt
            if((pRequest->CommandCode== 61)&& (TRUE==SDHCISFORCEATA(pController)))
            {
                DWORD waitStatus;
                RETAILMSG(1, (TEXT("HandleEndCommandInterrupt:Waiting for CCS\n")));
                //wait for CEATA CCS from GPIO input
                XllpGpioGetEdgeDetectStatus((pController->XllpMMCContext).pGPIOReg, XLLP_GPIO_MMC_CMD_0, &CCSStatus);
                if(CCSStatus)
		{
                    RETAILMSG(1, (TEXT("CEATA CCS received CCS -1,wait event SUCCESS, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));			
                    XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
                }
                else
                {
                    waitStatus = WaitForSingleObject(hCEATACCSIntrEvent, 5000);
                    switch (waitStatus)
                    {
                        case WAIT_OBJECT_0:
                            RETAILMSG(1, (TEXT("CEATA CCS received CCS -2,wait event SUCCESS, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));
                            XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
		            break;
                        case WAIT_TIMEOUT:
                            XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
                            //send CCSD
                            XllpMMCSendCEATACCSD(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
                            RETAILMSG(1, (TEXT("CEATA CCS: wait event, returns TIMEOUT, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));			
                            break;
                        default:
                            XllpMMCDisableCEATACCS(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
                            //send CCSD
                            XllpMMCSendCEATACCSD(&(pController->XllpMMCContext), XLLP_MMC_SLOT_0);
                            RETAILMSG(1, (TEXT("CEATA CCS: wait event, returns ERROR=%x \r\n"), GetLastError())); 
                            break;
                    }
                }
                RETAILMSG(1, (TEXT("CEATA enable CCS, gedr0=%x\r\n"),pController->pGPIORegisters->gedr0));
                RETAILMSG(1, (TEXT("CEATA enable CCS, gfer0=%x\r\n"),pController->pGPIORegisters->gfer0));
                RETAILMSG(1, (TEXT("CEATA enable CCS, gsfer0=%x\r\n"),pController->pGPIORegisters->gsfer0));
                RETAILMSG(1, (TEXT("CEATA enable CCS, gpdr0=%x\r\n"),pController->pGPIORegisters->gpdr0));
                ResetEvent(hCEATACCSIntrEvent);
                InterruptDone(SYSINTR_CEATACCS);
            }
#endif
        } else {
            DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt starting WRITE TRANSFER of %d blocks of %d bytes\r\n"), pRequest->NumBlocks, pRequest->BlockSize ));
            DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Bytes wrtn: [%S]\r\n"), HexDisplay(pRequest, pRequest->pBlockBuffer, TRANSFER_SIZE(pRequest) )) );
            SetCurrentState(pController, WriteDataTransfer);
            RETAILMSG(SDDEBUG,(TEXT("[SDH] SetCurrentState-WriteDataTransfer\r\n")));

                // turn on Fifo interrupts
#ifndef DMA_TEST_MODE
            TX_FIFO_INTERRUPT_ON(pController);
#endif
                // turn on transfer interrupts
            TRANSFER_DONE_INTERRUPT_ON(pController);
            SDLoadXmitFifo(pController, pRequest);
            
        }
    }
    
}

///////////////////////////////////////////////////////////////////////////////
//  HandleSDIOInterrupt - Handle SDIO interrupt
//  Input:  pController - the controller that is interrupting
//  Output: 
//  Return:
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
VOID HandleSDIOInterrupt(PSDH_HARDWARE_CONTEXT pHCDevice)
{
    ACQUIRE_LOCK(pHCDevice);

    if( pHCDevice->DevicePresent ) 
    {
            // disable the SDIO interrupt
        SDIO_INTERRUPT_OFF(pHCDevice);
            // indicate that the card is interrupting
        DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Got SDIO Interrupt\r\n")));
        SDHCDIndicateSlotStateChange(pHCDevice->pHCContext, 
                                        0,
                                        DeviceInterrupting);
    }

    RELEASE_LOCK(pHCDevice);
}


///////////////////////////////////////////////////////////////////////////////
//  GetMMCInterrupts - Get MMC interrupts
//  Input:  pHCDevice - the controller 
//  Output: 
//  Return: bit mask of the interrupts
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
DWORD GetMMCInterrupts(PSDH_HARDWARE_CONTEXT pHCDevice)
{
    DWORD intr;
    DWORD interrupts;    // current interrupts
    DWORD interruptMask; // interrupt mask
    DWORD stat;

        // get interrupts
    intr = READ_MMC_REGISTER_DWORD(pHCDevice, MMC_IREG) 
                 & MMC_IREG_INTERRUPTS;

    // get the interrupt masks so we know which ones we don't care about
        // the handlers will turn off (mask) interrupts 
    interruptMask = (~(READ_MMC_REGISTER_DWORD(pHCDevice, MMC_IMASK))) 
                    & MMC_IREG_INTERRUPTS;

        // mask it
    interrupts = intr & interruptMask;

    stat = pHCDevice->pSDMMCRegisters->stat;
                                     
    if( pHCDevice->fSDIOEnabled )
    {
        DbgPrintZo(SDH_INTERRUPT_ZONE, 
            (TEXT("S=%04X I=%04X M=%04X R=%04X\r\n"), 
                stat, intr, interruptMask, interrupts));
    }
    return interrupts;
}

///////////////////////////////////////////////////////////////////////////////
//  SDControllerIstThread - IST thread for MMC Controller driver
//  Input:  pHCDevice - the controller instance
//  Output: 
//  Return: Thread exit code
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
BOOL SDControllerISTHandler(PSDH_HARDWARE_CONTEXT pHCDevice, BOOL fTimeOut)
{
    DWORD interrupts;    // current interrupts
    DWORD interruptMask;
    BOOL  fForceTimeout;
    DbgPrintZo(SDH_INTERRUPT_ZONE, (TEXT("SDControllerISTHandler+++++++++++++ \n")));

    interrupts = GetMMCInterrupts(pHCDevice);
    RETAILMSG(SDDEBUG,  (TEXT("[%s] SDControllerISTHandler+++++++++++++,intr:0x%x \n"), pHCDevice->szName, interrupts));
    // We have observed that sometimes, after an abrupt card removal and insert,
    // the controller will "stall" during the first data transfer, there will be
    // no hardware timeout.  If this is the case, we will simulate a hardware timeout 
    // interrupt.
    fForceTimeout = FALSE;
    if (fTimeOut) {
        // check if the MMC_IREG_DAT_ERR interrupt is enabled 
        interruptMask = (~(READ_MMC_REGISTER_DWORD(pHCDevice, MMC_IMASK))) 
                        & MMC_IREG_INTERRUPTS;
        if( interruptMask & MMC_IREG_DAT_ERR )
        {
            DbgPrintZo(SDCARD_ZONE_WARN, 
                (TEXT("SDControllerIstHandler: Unexpected hardware timeout!\n")));
            interrupts |= MMC_IREG_DAT_ERR;
            fForceTimeout = TRUE;
        }
        }
        

            // loop until all interrupts are serviced
    while (interrupts) {
            DbgPrintZo(SDH_INTERRUPT_ZONE, 
                (TEXT("SDControllerIstHandler: Controller Interrupt: 0x%08X \r\n"),interrupts));

            if (interrupts & MMC_IREG_TINT) {
                    // no one should be turning this on
                DEBUG_ASSERT(FALSE);
            }

            if (interrupts & MMC_IREG_DAT_ERR) {
                    // no one should be turning this on
                DEBUG_ASSERT(FALSE);
            }

            if (interrupts & MMC_IREG_RES_ERR) {
                    // no one should be turning this on
                DEBUG_ASSERT(FALSE);
            }

            if (interrupts & MMC_IREG_RD_STALLED) {
                    // no one should be turning this on
                DEBUG_ASSERT(FALSE);
            }

            if (interrupts & MMC_IREG_SDIO_SUSPEND_ACK) {
                    // no one should be turning this on
                DEBUG_ASSERT(FALSE);
            }

            if (interrupts & MMC_IREG_CLOCK_IS_OFF) {
                    // no one should be turning this on
                DEBUG_ASSERT(FALSE);
                    // mask the interrupt
                CLOCK_OFF_INTERRUPT_OFF(pHCDevice);
            }
   
            if (interrupts & MMC_IREG_END_CMD) {
                DbgPrintZo(SDH_INTERRUPT_ZONE, 
                    (TEXT("SDControllerIstHandler: MMC_IREG_END_CMD \r\n")));
                HandleEndCommandInterrupt(pHCDevice);
            }
            
            if (interrupts & MMC_IREG_STOP_CMD) {
                DbgPrintZo(SDH_INTERRUPT_ZONE, 
                    (TEXT("SDControllerIstHandler: MMC_IREG_STOP_CMD \r\n")));
                DEBUG_ASSERT(FALSE);
            }
            
            if (interrupts & MMC_IREG_RXFIFO_REQ ) {
                DbgPrintZo(SDH_INTERRUPT_ZONE, 
                    (TEXT("SDControllerIstHandler: MMC_IREG_RXFIFO_REQ \r\n")));
                HandleReceiveInterrupt(pHCDevice);
            }
            
            if (interrupts & MMC_IREG_TXFIFO_REQ) {
                DbgPrintZo(SDH_INTERRUPT_ZONE, 
                    (TEXT("SDControllerIstHandler: MMC_IREG_TXFIFO_REQ \r\n")));
                HandleXmitInterrupt(pHCDevice);
            }
            
            if (interrupts & MMC_IREG_PROG_DONE) {
                DbgPrintZo(SDH_INTERRUPT_ZONE, 
                    (TEXT("SDControllerIstHandler: MMC_IREG_PROG_DONE \r\n")));
                HandleProgramDone(pHCDevice);
            } 
                // DATA transfer done should be checked last so that the 
                // HandleReceive and HandleTransmit
                // have a chance to finish copying from the fifos
            if (interrupts & MMC_IREG_DATA_TRAN_DONE) {
                DbgPrintZo(SDH_INTERRUPT_ZONE, 
                    (TEXT("SDControllerIstHandler: MMC_IREG_DATA_TRAN_DONE \r\n")));
                HandleTransferDone(pHCDevice, fForceTimeout);
            }

            if (interrupts & MMC_IREG_SDIO_INT) {
                DbgPrintZo(SDH_INTERRUPT_ZONE, 
                    (TEXT("SDControllerIstHandler: MMC_IREG_SDIO_INT \r\n")));
                HandleSDIOInterrupt(pHCDevice);
            } 

        interrupts = GetMMCInterrupts(pHCDevice);
    } // while
    DbgPrintZo(SDH_INTERRUPT_ZONE, (TEXT("SDControllerISTHandler-------------- \n")));
    RETAILMSG(SDDEBUG, (TEXT("SDControllerISTHandler-------------- \n")));
    return TRUE;
        }
///////////////////////////////////////////////////////////////////////////////
//  SDControllerIstThread - IST thread for MMC Controller driver
//  Input:  pHCDevice - the controller instance
//  Output: 
//  Return: Thread exit code
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
DWORD SDControllerIstThread(PSDH_HARDWARE_CONTEXT pHCDevice)
            {
    DWORD waitStatus;    // wait status

    if (!CeSetThreadPriority(GetCurrentThread(), 
        pHCDevice->ControllerIstThreadPriority)) {
        DbgPrintZo(SDCARD_ZONE_WARN, 
            (TEXT("SDControllerIstThread: warning, failed to set CEThreadPriority \n")));
            }

    while(1) {
        waitStatus = WaitForSingleObject(pHCDevice->hControllerInterruptEvent, 
                                         INFINITE);

        if (WAIT_FAILED == waitStatus) {
            DbgPrintZo(SDCARD_ZONE_WARN, 
                (TEXT("SDControllerIstThread: Wait Failed! 0x%08X \n"), waitStatus));
                // bail out
            return 0;
        }

        if (pHCDevice->DriverShutdown) {
            DbgPrintZo(1, (TEXT("SDControllerIstThread: Thread Exiting\n")));
            return 0;
        }
        ACQUIRE_LOCK(pHCDevice);
        SDControllerISTHandler(pHCDevice, waitStatus != WAIT_OBJECT_0 );
        RELEASE_LOCK(pHCDevice);
        InterruptDone(pHCDevice->dwSysintrSDMMC);
    }

}


void ProcessCardInsertion( void *pContext )
{
    DWORD initializationClock = SD_DEFAULT_CARD_ID_CLOCK_RATE;
    PSDH_HARDWARE_CONTEXT pHCDevice = (PSDH_HARDWARE_CONTEXT)pContext;

	
    if (!pHCDevice->DevicePresent) {
		
        RETAILMSG(1, (TEXT("[%s] ProcessCardInsertion() \r\n"), pHCDevice->szName)); 

        /* Check if it need to reset WLAN  */
	    if ( TRUE == IsSDHForWLAN(pHCDevice))
		{
			NKDbgPrintfW(TEXT("[MMC] ProcessCardInsertion WLAN_PowerOn\r\n"));					
			WLAN_PowerOn(pHCDevice);
		}			

            // if we have stable insertion and there wasn't a device mark it
        DbgPrintZo(SDH_INTERRUPT_ZONE, 
            (TEXT("CardDetectIstThread: Device Fully Inserted ! \r\n"))); 
        RETAILMSG(1,(TEXT("[%s] CardDetectIstThread: Device Fully Inserted ! \r\n"), pHCDevice->szName)); 
            // mark that the card is in the slot
        pHCDevice->DevicePresent = TRUE;
			
        pHCDevice->gPowerState = D0;
    
            // flag that this is the first command sent
        pHCDevice->SendInitClocks = TRUE;

	 //sometimes it cost >2 s from to busdriver start to sent cmd
        // set it active to avoid clk off during remove-(waiting for timeout)-insert-(timeout)-issue cmd
        pHCDevice->fCMD= TRUE;

        RETAILMSG(SDDEBUG, (TEXT("turn off cken")));
        // enable the MMC Unit Clock, will disable when card is removed
	 //   XllpClockEnable((P_XLLP_CLKMGR_T)pHCDevice->pClkMgrRegisters, pHCDevice->MMCClkModule, XLLP_TRUE);

        SDCKENOnOff(pHCDevice, FALSE);
		
            // turn the Multimedia Card power on
        MMCPowerControl(pHCDevice, TRUE );

            // reset the clock to the ID rate
            // shut off clock first
        //SDClockOff(pHCDevice);
            // set rate
        SDSetRate(pHCDevice, &initializationClock);
        pHCDevice->dwWorkClkRate=pHCDevice->dwSDClockFrequency;
 
            // give the card some time for initialization
        Sleep(100);

            // indicate the slot change
        SDHCDIndicateSlotStateChange(pHCDevice->pHCContext, 
                                        0,
                                        DeviceInserted);
    }
}

void ProcessCardRemoval( void *pContext )
{
    PSDH_HARDWARE_CONTEXT pHCDevice = (PSDH_HARDWARE_CONTEXT)pContext;
    PSD_BUS_REQUEST pRequest;       // current request
#ifdef DMA_TEST_MODE
    PSDHCDmacDescriptor pSDHCDmacDscr=(PSDHCDmacDescriptor)pHCDevice->DmacDscr;
#endif

    if( pHCDevice->DevicePresent )
    {
        RETAILMSG(1, (TEXT("[%s] ProcessCardRemoval()\r\n"), pHCDevice->szName)); 
    
        /* Check if it need to power off WLAN  */
	    if ( TRUE == IsSDHForWLAN(pHCDevice))
		{
			NKDbgPrintfW(TEXT("[MMC] ProcessCardInsertion WLAN_PowerOff\r\n"));					
			WLAN_PowerOff(pHCDevice);
		}			

        DbgPrintZo(SDH_INTERRUPT_ZONE, 
            (TEXT("CardDetectIstThread: Card Removal Detected! \r\n"))); 
        RETAILMSG(1,(TEXT("[%s] CardDetectIstThread: Card Removal Detected! \r\n"), pHCDevice->szName)); 
		
            // mark that the card has been removed
        pHCDevice->DevicePresent = FALSE;
            
            // indicate the slot change 
        SDHCDIndicateSlotStateChange(pHCDevice->pHCContext, 
                                        0,
                                        DeviceEjected); 

            // shut off clock first
        SDClockOff(pHCDevice);

        // Complete any pending request
        if((pRequest = pHCDevice->pCurrentRequest) != NULL)
        {
            ALL_INTERRUPTS_OFF(pHCDevice);

#ifdef DMA_TEST_MODE
            // Stop the Transfer.

            if (TRANSFER_IS_READ(pRequest))
                XllpDmacStopTransfer(pSDHCDmacDscr->pDMACHandle, pSDHCDmacDscr->RcvChannel );
            else if (TRANSFER_IS_WRITE(pRequest))			
                XllpDmacStopTransfer(pSDHCDmacDscr->pDMACHandle, pSDHCDmacDscr->XmtChannel );				
#endif 

            IndicateBusRequestComplete(pHCDevice->pHCContext,
                                            pRequest ,
                                            SD_API_STATUS_DEVICE_REMOVED);
        }

        // turn the Multimedia Card power off
        MMCPowerControl(pHCDevice, FALSE );

        RETAILMSG(SDDEBUG, (TEXT("turn off cken")));
        // disable the MMC Unit Clock, will enable when card is inserted       
        //XllpClockEnable((P_XLLP_CLKMGR_T)pHCDevice->pClkMgrRegisters, pHCDevice->MMCClkModule, XLLP_FALSE);
       SDCKENOnOff(pHCDevice, FALSE);
    }
}

BOOL DriverShutdown(void *pContext)
{
    PSDH_HARDWARE_CONTEXT pHCDevice = (PSDH_HARDWARE_CONTEXT)pContext;
    return pHCDevice->DriverShutdown;
}

void SDControllerPowerDown(PSDH_HARDWARE_CONTEXT pHCDevice)
{
    ASSERT( pHCDevice );
    if( !pHCDevice )
        return;

    // Notify the SD Bus driver of the PowerDown event
    // this will result a 30s+ suspend delay when play media on sdcard
    // it maybe because that this function ask slot to be rejected when playing and result a long timeout/wait

    // shut off clock first
    SDClockOff(pHCDevice);

    MMCSlotPowerSet(pHCDevice, FALSE);

    // turn the Multimedia Card power on
    MMCPowerControl(pHCDevice, FALSE );
}

void SDControllerPowerUp(PSDH_HARDWARE_CONTEXT pHCDevice)
{
    ASSERT( pHCDevice );
    if( !pHCDevice )
        return;

    // Notify the SD Bus driver of the PowerUp event
    MMCSlotPowerSet(pHCDevice, TRUE);

    // simulate a card ejection/insertion
    SimulateCardInsertion(pHCDevice);

}


#ifdef DDEBUG // Disabled for now
void DumpRegisters(PSDH_HARDWARE_CONTEXT pController)
{
    BOOL fQuit = TRUE;
#ifdef EXTENSIVE_DEBUGGING
    fQuit = FALSE;
#endif
    if( !fQuit )
    {
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("SD/MMC Registers Dump Begin\r\n")));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("STRPC =0x%08X\n"), pController->pSDMMCRegisters->strpc));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("STAT  =0x%08X\n"), pController->pSDMMCRegisters->stat));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("CLKRT =0x%08X\n"), pController->pSDMMCRegisters->clkrt));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("SPI   =0x%08X\n"), pController->pSDMMCRegisters->spi));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("CMDAT =0x%08X\n"), pController->pSDMMCRegisters->cmdat));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("RESTO =0x%08X\n"), pController->pSDMMCRegisters->resto));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("RDTO  =0x%08X\n"), pController->pSDMMCRegisters->rdto));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("BLKLE =0x%08X\n"), pController->pSDMMCRegisters->blkle));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("NOB   =0x%08X\n"), pController->pSDMMCRegisters->nob));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("PRTBU =0x%08X\n"), pController->pSDMMCRegisters->prtbu));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("IMASK =0x%08X\n"), pController->pSDMMCRegisters->imask));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("IREG  =0x%08X\n"), pController->pSDMMCRegisters->ireg));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("CMD   =0x%08X\n"), pController->pSDMMCRegisters->cmd));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("ARGH  =0x%08X\n"), pController->pSDMMCRegisters->argh));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("ARGL  =0x%08X\n"), pController->pSDMMCRegisters->argl));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("RES   =0x%08X\n"), pController->pSDMMCRegisters->res));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("RXFIFO=----------\n")/*, pController->pSDMMCRegisters->rxfifo*/));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("TXFIFO=----------\n")/*, pController->pSDMMCRegisters->txfifo*/));
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("SD/MMC Registers Dump End\r\n")));
    }
}

void DumpGPIORegisters(PSDH_HARDWARE_CONTEXT pController)
{
    BOOL fQuit = TRUE;
#ifdef EXTENSIVE_DEBUGGING
    fQuit = FALSE;
#endif
    if( !fQuit )
    {
        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("GPIO Registers Dump Begin\r\n")));

        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("Alt. Function Select Registers:\n GAFR0_L=0x%08X, GAFR1_L=0x%08X, GAFR2_L=0x%08X, GAFR3_L=0x%08X\n GAFR0_U=0x%08X, GAFR1_U=0x%08X, GAFR2_U=0x%08X, GAFR3_U=0x%08X\n"),
            pController->pGPIORegisters->GAFR0_L, pController->pGPIORegisters->GAFR1_L, pController->pGPIORegisters->GAFR2_L, pController->pGPIORegisters->GAFR3_L,
            pController->pGPIORegisters->GAFR0_U, pController->pGPIORegisters->GAFR1_U, pController->pGPIORegisters->GAFR2_U, pController->pGPIORegisters->GAFR3_U));

        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("Pin direction Registers:\n GPDR0=0x%08X, GPDR1=0x%08X, GPDR2=0x%08X, GPDR3=0x%08X\n"),
            pController->pGPIORegisters->GPDR0, pController->pGPIORegisters->GPDR1, pController->pGPIORegisters->GPDR2, pController->pGPIORegisters->GPDR3));

        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("Pin Level Registers:\n GPLR0=0x%08X, GPLR1=0x%08X, GPLR2=0x%08X, GPLR3=0x%08X\n"),
            pController->pGPIORegisters->GPLR0, pController->pGPIORegisters->GPLR1, pController->pGPIORegisters->GPLR2, pController->pGPIORegisters->GPLR3));

        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("Pin Rising Edge Detect Enable Registers:\n GRER0=0x%08X, GRER1=0x%08X, GRER2=0x%08X, GRER3=0x%08X\n"),
            pController->pGPIORegisters->GRER0, pController->pGPIORegisters->GRER1, pController->pGPIORegisters->GRER2, pController->pGPIORegisters->GRER3));

        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("Pin Falling Edge Detect Enable Registers:\n GFER0=0x%08X, GFER1=0x%08X, GFER2=0x%08X, GFER3=0x%08X\n"),
            pController->pGPIORegisters->GFER0, pController->pGPIORegisters->GFER1, pController->pGPIORegisters->GFER2, pController->pGPIORegisters->GFER3));

        DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("GPIO Registers Dump End\r\n")));
    }
}

#endif

// DO NOT REMOVE --- END EXTERNALLY DEVELOPED SOURCE CODE ID --- DO NOT REMOVE
